Mercurial > libervia-backend
comparison sat/core/sat_main.py @ 4037:524856bd7b19
massive refactoring to switch from camelCase to snake_case:
historically, Libervia (SàT before) was using camelCase as allowed by PEP8 when using a
pre-PEP8 code, to use the same coding style as in Twisted.
However, snake_case is more readable and it's better to follow PEP8 best practices, so it
has been decided to move on full snake_case. Because Libervia has a huge codebase, this
ended with a ugly mix of camelCase and snake_case.
To fix that, this patch does a big refactoring by renaming every function and method
(including bridge) that are not coming from Twisted or Wokkel, to use fully snake_case.
This is a massive change, and may result in some bugs.
author | Goffi <goffi@goffi.org> |
---|---|
date | Sat, 08 Apr 2023 13:54:42 +0200 |
parents | 7bf7677b893d |
children | 2594e1951cf7 |
comparison
equal
deleted
inserted
replaced
4036:c4464d7ae97b | 4037:524856bd7b19 |
---|---|
24 from pathlib import Path | 24 from pathlib import Path |
25 from typing import Optional, List, Tuple, Dict | 25 from typing import Optional, List, Tuple, Dict |
26 | 26 |
27 from wokkel.data_form import Option | 27 from wokkel.data_form import Option |
28 import sat | 28 import sat |
29 from sat.core.i18n import _, D_, languageSwitch | 29 from sat.core.i18n import _, D_, language_switch |
30 from sat.core import patches | 30 from sat.core import patches |
31 patches.apply() | 31 patches.apply() |
32 from twisted.application import service | 32 from twisted.application import service |
33 from twisted.internet import defer | 33 from twisted.internet import defer |
34 from twisted.words.protocols.jabber import jid | 34 from twisted.words.protocols.jabber import jid |
67 # value: menu id | 67 # value: menu id |
68 self.initialised = defer.Deferred() | 68 self.initialised = defer.Deferred() |
69 self.profiles = {} | 69 self.profiles = {} |
70 self.plugins = {} | 70 self.plugins = {} |
71 # map for short name to whole namespace, | 71 # map for short name to whole namespace, |
72 # extended by plugins with registerNamespace | 72 # extended by plugins with register_namespace |
73 self.ns_map = { | 73 self.ns_map = { |
74 "x-data": xmpp.NS_X_DATA, | 74 "x-data": xmpp.NS_X_DATA, |
75 "disco#info": xmpp.NS_DISCO_INFO, | 75 "disco#info": xmpp.NS_DISCO_INFO, |
76 } | 76 } |
77 | 77 |
82 trigger.TriggerManager() | 82 trigger.TriggerManager() |
83 ) | 83 ) |
84 | 84 |
85 bridge_name = ( | 85 bridge_name = ( |
86 os.getenv("LIBERVIA_BRIDGE_NAME") | 86 os.getenv("LIBERVIA_BRIDGE_NAME") |
87 or self.memory.getConfig("", "bridge", "dbus") | 87 or self.memory.config_get("", "bridge", "dbus") |
88 ) | 88 ) |
89 | 89 |
90 bridge_module = dynamic_import.bridge(bridge_name) | 90 bridge_module = dynamic_import.bridge(bridge_name) |
91 if bridge_module is None: | 91 if bridge_module is None: |
92 log.error(f"Can't find bridge module of name {bridge_name}") | 92 log.error(f"Can't find bridge module of name {bridge_name}") |
93 sys.exit(1) | 93 sys.exit(1) |
94 log.info(f"using {bridge_name} bridge") | 94 log.info(f"using {bridge_name} bridge") |
95 try: | 95 try: |
96 self.bridge = bridge_module.Bridge() | 96 self.bridge = bridge_module.bridge() |
97 except exceptions.BridgeInitError: | 97 except exceptions.BridgeInitError: |
98 log.exception("Bridge can't be initialised, can't start Libervia Backend") | 98 log.exception("bridge can't be initialised, can't start Libervia Backend") |
99 sys.exit(1) | 99 sys.exit(1) |
100 | 100 |
101 defer.ensureDeferred(self._post_init()) | 101 defer.ensureDeferred(self._post_init()) |
102 | 102 |
103 @property | 103 @property |
116 # we are in debug version, we add extra data | 116 # we are in debug version, we add extra data |
117 try: | 117 try: |
118 return self._version_cache | 118 return self._version_cache |
119 except AttributeError: | 119 except AttributeError: |
120 self._version_cache = "{} « {} » ({})".format( | 120 self._version_cache = "{} « {} » ({})".format( |
121 version, C.APP_RELEASE_NAME, utils.getRepositoryData(sat) | 121 version, C.APP_RELEASE_NAME, utils.get_repository_data(sat) |
122 ) | 122 ) |
123 return self._version_cache | 123 return self._version_cache |
124 else: | 124 else: |
125 return version | 125 return version |
126 | 126 |
128 def bridge_name(self): | 128 def bridge_name(self): |
129 return os.path.splitext(os.path.basename(self.bridge.__file__))[0] | 129 return os.path.splitext(os.path.basename(self.bridge.__file__))[0] |
130 | 130 |
131 async def _post_init(self): | 131 async def _post_init(self): |
132 try: | 132 try: |
133 bridge_pi = self.bridge.postInit | 133 bridge_pi = self.bridge.post_init |
134 except AttributeError: | 134 except AttributeError: |
135 pass | 135 pass |
136 else: | 136 else: |
137 try: | 137 try: |
138 await bridge_pi() | 138 await bridge_pi() |
140 log.exception("Could not initialize bridge") | 140 log.exception("Could not initialize bridge") |
141 # because init is not complete at this stage, we use callLater | 141 # because init is not complete at this stage, we use callLater |
142 reactor.callLater(0, self.stop) | 142 reactor.callLater(0, self.stop) |
143 return | 143 return |
144 | 144 |
145 self.bridge.register_method("getReady", lambda: self.initialised) | 145 self.bridge.register_method("ready_get", lambda: self.initialised) |
146 self.bridge.register_method("getVersion", lambda: self.full_version) | 146 self.bridge.register_method("version_get", lambda: self.full_version) |
147 self.bridge.register_method("getFeatures", self.getFeatures) | 147 self.bridge.register_method("features_get", self.features_get) |
148 self.bridge.register_method("profileNameGet", self.memory.getProfileName) | 148 self.bridge.register_method("profile_name_get", self.memory.get_profile_name) |
149 self.bridge.register_method("profilesListGet", self.memory.getProfilesList) | 149 self.bridge.register_method("profiles_list_get", self.memory.get_profiles_list) |
150 self.bridge.register_method("getEntityData", self.memory._getEntityData) | 150 self.bridge.register_method("entity_data_get", self.memory._get_entity_data) |
151 self.bridge.register_method("getEntitiesData", self.memory._getEntitiesData) | 151 self.bridge.register_method("entities_data_get", self.memory._get_entities_data) |
152 self.bridge.register_method("profileCreate", self.memory.createProfile) | 152 self.bridge.register_method("profile_create", self.memory.create_profile) |
153 self.bridge.register_method("asyncDeleteProfile", self.memory.asyncDeleteProfile) | 153 self.bridge.register_method("profile_delete_async", self.memory.profile_delete_async) |
154 self.bridge.register_method("profileStartSession", self.memory.startSession) | 154 self.bridge.register_method("profile_start_session", self.memory.start_session) |
155 self.bridge.register_method( | 155 self.bridge.register_method( |
156 "profileIsSessionStarted", self.memory._isSessionStarted | 156 "profile_is_session_started", self.memory._is_session_started |
157 ) | 157 ) |
158 self.bridge.register_method("profileSetDefault", self.memory.profileSetDefault) | 158 self.bridge.register_method("profile_set_default", self.memory.profile_set_default) |
159 self.bridge.register_method("connect", self._connect) | 159 self.bridge.register_method("connect", self._connect) |
160 self.bridge.register_method("disconnect", self.disconnect) | 160 self.bridge.register_method("disconnect", self.disconnect) |
161 self.bridge.register_method("contactGet", self._contactGet) | 161 self.bridge.register_method("contact_get", self._contact_get) |
162 self.bridge.register_method("getContacts", self.getContacts) | 162 self.bridge.register_method("contacts_get", self.contacts_get) |
163 self.bridge.register_method("getContactsFromGroup", self.getContactsFromGroup) | 163 self.bridge.register_method("contacts_get_from_group", self.contacts_get_from_group) |
164 self.bridge.register_method("getMainResource", self.memory._getMainResource) | 164 self.bridge.register_method("main_resource_get", self.memory._get_main_resource) |
165 self.bridge.register_method( | 165 self.bridge.register_method( |
166 "getPresenceStatuses", self.memory._getPresenceStatuses | 166 "presence_statuses_get", self.memory._get_presence_statuses |
167 ) | 167 ) |
168 self.bridge.register_method("getWaitingSub", self.memory.getWaitingSub) | 168 self.bridge.register_method("sub_waiting_get", self.memory.sub_waiting_get) |
169 self.bridge.register_method("messageSend", self._messageSend) | 169 self.bridge.register_method("message_send", self._message_send) |
170 self.bridge.register_method("messageEncryptionStart", | 170 self.bridge.register_method("message_encryption_start", |
171 self._messageEncryptionStart) | 171 self._message_encryption_start) |
172 self.bridge.register_method("messageEncryptionStop", | 172 self.bridge.register_method("message_encryption_stop", |
173 self._messageEncryptionStop) | 173 self._message_encryption_stop) |
174 self.bridge.register_method("messageEncryptionGet", | 174 self.bridge.register_method("message_encryption_get", |
175 self._messageEncryptionGet) | 175 self._message_encryption_get) |
176 self.bridge.register_method("encryptionNamespaceGet", | 176 self.bridge.register_method("encryption_namespace_get", |
177 self._encryptionNamespaceGet) | 177 self._encryption_namespace_get) |
178 self.bridge.register_method("encryptionPluginsGet", self._encryptionPluginsGet) | 178 self.bridge.register_method("encryption_plugins_get", self._encryption_plugins_get) |
179 self.bridge.register_method("encryptionTrustUIGet", self._encryptionTrustUIGet) | 179 self.bridge.register_method("encryption_trust_ui_get", self._encryption_trust_ui_get) |
180 self.bridge.register_method("getConfig", self._getConfig) | 180 self.bridge.register_method("config_get", self._get_config) |
181 self.bridge.register_method("setParam", self.setParam) | 181 self.bridge.register_method("param_set", self.param_set) |
182 self.bridge.register_method("getParamA", self.memory.getStringParamA) | 182 self.bridge.register_method("param_get_a", self.memory.get_string_param_a) |
183 self.bridge.register_method("privateDataGet", self.memory._privateDataGet) | 183 self.bridge.register_method("private_data_get", self.memory._private_data_get) |
184 self.bridge.register_method("privateDataSet", self.memory._privateDataSet) | 184 self.bridge.register_method("private_data_set", self.memory._private_data_set) |
185 self.bridge.register_method("privateDataDelete", self.memory._privateDataDelete) | 185 self.bridge.register_method("private_data_delete", self.memory._private_data_delete) |
186 self.bridge.register_method("asyncGetParamA", self.memory.asyncGetStringParamA) | 186 self.bridge.register_method("param_get_a_async", self.memory.async_get_string_param_a) |
187 self.bridge.register_method( | 187 self.bridge.register_method( |
188 "asyncGetParamsValuesFromCategory", | 188 "params_values_from_category_get_async", |
189 self.memory._getParamsValuesFromCategory, | 189 self.memory._get_params_values_from_category, |
190 ) | 190 ) |
191 self.bridge.register_method("getParamsUI", self.memory._getParamsUI) | 191 self.bridge.register_method("param_ui_get", self.memory._get_params_ui) |
192 self.bridge.register_method( | 192 self.bridge.register_method( |
193 "getParamsCategories", self.memory.getParamsCategories | 193 "params_categories_get", self.memory.params_categories_get |
194 ) | 194 ) |
195 self.bridge.register_method("paramsRegisterApp", self.memory.paramsRegisterApp) | 195 self.bridge.register_method("params_register_app", self.memory.params_register_app) |
196 self.bridge.register_method("historyGet", self.memory._historyGet) | 196 self.bridge.register_method("history_get", self.memory._history_get) |
197 self.bridge.register_method("setPresence", self._setPresence) | 197 self.bridge.register_method("presence_set", self._set_presence) |
198 self.bridge.register_method("subscription", self.subscription) | 198 self.bridge.register_method("subscription", self.subscription) |
199 self.bridge.register_method("addContact", self._addContact) | 199 self.bridge.register_method("contact_add", self._add_contact) |
200 self.bridge.register_method("updateContact", self._updateContact) | 200 self.bridge.register_method("contact_update", self._update_contact) |
201 self.bridge.register_method("delContact", self._delContact) | 201 self.bridge.register_method("contact_del", self._del_contact) |
202 self.bridge.register_method("rosterResync", self._rosterResync) | 202 self.bridge.register_method("roster_resync", self._roster_resync) |
203 self.bridge.register_method("isConnected", self.isConnected) | 203 self.bridge.register_method("is_connected", self.is_connected) |
204 self.bridge.register_method("launchAction", self.launchCallback) | 204 self.bridge.register_method("action_launch", self.launch_callback) |
205 self.bridge.register_method("actionsGet", self.actionsGet) | 205 self.bridge.register_method("actions_get", self.actions_get) |
206 self.bridge.register_method("progressGet", self._progressGet) | 206 self.bridge.register_method("progress_get", self._progress_get) |
207 self.bridge.register_method("progressGetAll", self._progressGetAll) | 207 self.bridge.register_method("progress_get_all", self._progress_get_all) |
208 self.bridge.register_method("menusGet", self.getMenus) | 208 self.bridge.register_method("menus_get", self.get_menus) |
209 self.bridge.register_method("menuHelpGet", self.getMenuHelp) | 209 self.bridge.register_method("menu_help_get", self.get_menu_help) |
210 self.bridge.register_method("menuLaunch", self._launchMenu) | 210 self.bridge.register_method("menu_launch", self._launch_menu) |
211 self.bridge.register_method("discoInfos", self.memory.disco._discoInfos) | 211 self.bridge.register_method("disco_infos", self.memory.disco._disco_infos) |
212 self.bridge.register_method("discoItems", self.memory.disco._discoItems) | 212 self.bridge.register_method("disco_items", self.memory.disco._disco_items) |
213 self.bridge.register_method("discoFindByFeatures", self._findByFeatures) | 213 self.bridge.register_method("disco_find_by_features", self._find_by_features) |
214 self.bridge.register_method("saveParamsTemplate", self.memory.save_xml) | 214 self.bridge.register_method("params_template_save", self.memory.save_xml) |
215 self.bridge.register_method("loadParamsTemplate", self.memory.load_xml) | 215 self.bridge.register_method("params_template_load", self.memory.load_xml) |
216 self.bridge.register_method("sessionInfosGet", self.getSessionInfos) | 216 self.bridge.register_method("session_infos_get", self.get_session_infos) |
217 self.bridge.register_method("devicesInfosGet", self._getDevicesInfos) | 217 self.bridge.register_method("devices_infos_get", self._get_devices_infos) |
218 self.bridge.register_method("namespacesGet", self.getNamespaces) | 218 self.bridge.register_method("namespaces_get", self.get_namespaces) |
219 self.bridge.register_method("imageCheck", self._imageCheck) | 219 self.bridge.register_method("image_check", self._image_check) |
220 self.bridge.register_method("imageResize", self._imageResize) | 220 self.bridge.register_method("image_resize", self._image_resize) |
221 self.bridge.register_method("imageGeneratePreview", self._imageGeneratePreview) | 221 self.bridge.register_method("image_generate_preview", self._image_generate_preview) |
222 self.bridge.register_method("imageConvert", self._imageConvert) | 222 self.bridge.register_method("image_convert", self._image_convert) |
223 | 223 |
224 | 224 |
225 await self.memory.initialise() | 225 await self.memory.initialise() |
226 self.common_cache = cache.Cache(self, None) | 226 self.common_cache = cache.Cache(self, None) |
227 log.info(_("Memory initialised")) | 227 log.info(_("Memory initialised")) |
230 ui_contact_list.ContactList(self) | 230 ui_contact_list.ContactList(self) |
231 ui_profile_manager.ProfileManager(self) | 231 ui_profile_manager.ProfileManager(self) |
232 except Exception as e: | 232 except Exception as e: |
233 log.error(f"Could not initialize backend: {e}") | 233 log.error(f"Could not initialize backend: {e}") |
234 sys.exit(1) | 234 sys.exit(1) |
235 self._addBaseMenus() | 235 self._add_base_menus() |
236 | 236 |
237 self.initialised.callback(None) | 237 self.initialised.callback(None) |
238 log.info(_("Backend is ready")) | 238 log.info(_("Backend is ready")) |
239 | 239 |
240 # profile autoconnection must be done after self.initialised is called because | 240 # profile autoconnection must be done after self.initialised is called because |
241 # startSession waits for it. | 241 # start_session waits for it. |
242 autoconnect_dict = await self.memory.storage.getIndParamValues( | 242 autoconnect_dict = await self.memory.storage.get_ind_param_values( |
243 category='Connection', name='autoconnect_backend', | 243 category='Connection', name='autoconnect_backend', |
244 ) | 244 ) |
245 profiles_autoconnect = [p for p, v in autoconnect_dict.items() if C.bool(v)] | 245 profiles_autoconnect = [p for p, v in autoconnect_dict.items() if C.bool(v)] |
246 if not self.trigger.point("profilesAutoconnect", profiles_autoconnect): | 246 if not self.trigger.point("profilesAutoconnect", profiles_autoconnect): |
247 return | 247 return |
262 _("Can't autoconnect profile {profile}: {reason}").format( | 262 _("Can't autoconnect profile {profile}: {reason}").format( |
263 profile = profile, | 263 profile = profile, |
264 reason = result) | 264 reason = result) |
265 ) | 265 ) |
266 | 266 |
267 def _addBaseMenus(self): | 267 def _add_base_menus(self): |
268 """Add base menus""" | 268 """Add base menus""" |
269 encryption.EncryptionHandler._importMenus(self) | 269 encryption.EncryptionHandler._import_menus(self) |
270 | 270 |
271 def _unimport_plugin(self, plugin_path): | 271 def _unimport_plugin(self, plugin_path): |
272 """remove a plugin from sys.modules if it is there""" | 272 """remove a plugin from sys.modules if it is there""" |
273 try: | 273 try: |
274 del sys.modules[plugin_path] | 274 del sys.modules[plugin_path] |
275 except KeyError: | 275 except KeyError: |
276 pass | 276 pass |
277 | 277 |
278 def _import_plugins(self): | 278 def _import_plugins(self): |
279 """Import all plugins found in plugins directory""" | 279 """import all plugins found in plugins directory""" |
280 # FIXME: module imported but cancelled should be deleted | 280 # FIXME: module imported but cancelled should be deleted |
281 # TODO: make this more generic and reusable in tools.common | 281 # TODO: make this more generic and reusable in tools.common |
282 # FIXME: should use imp | 282 # FIXME: should use imp |
283 # TODO: do not import all plugins if no needed: component plugins are not needed | 283 # TODO: do not import all plugins if no needed: component plugins are not needed |
284 # if we just use a client, and plugin blacklisting should be possible in | 284 # if we just use a client, and plugin blacklisting should be possible in |
444 self.plugins[import_name].is_handler = False | 444 self.plugins[import_name].is_handler = False |
445 # we keep metadata as a Class attribute | 445 # we keep metadata as a Class attribute |
446 self.plugins[import_name]._info = plugin_info | 446 self.plugins[import_name]._info = plugin_info |
447 # TODO: test xmppclient presence and register handler parent | 447 # TODO: test xmppclient presence and register handler parent |
448 | 448 |
449 def pluginsUnload(self): | 449 def plugins_unload(self): |
450 """Call unload method on every loaded plugin, if exists | 450 """Call unload method on every loaded plugin, if exists |
451 | 451 |
452 @return (D): A deferred which return None when all method have been called | 452 @return (D): A deferred which return None when all method have been called |
453 """ | 453 """ |
454 # TODO: in the futur, it should be possible to hot unload a plugin | 454 # TODO: in the futur, it should be possible to hot unload a plugin |
459 try: | 459 try: |
460 unload = plugin.unload | 460 unload = plugin.unload |
461 except AttributeError: | 461 except AttributeError: |
462 continue | 462 continue |
463 else: | 463 else: |
464 defers_list.append(utils.asDeferred(unload)) | 464 defers_list.append(utils.as_deferred(unload)) |
465 return defers_list | 465 return defers_list |
466 | 466 |
467 def _connect(self, profile_key, password="", options=None): | 467 def _connect(self, profile_key, password="", options=None): |
468 profile = self.memory.getProfileName(profile_key) | 468 profile = self.memory.get_profile_name(profile_key) |
469 return defer.ensureDeferred(self.connect(profile, password, options)) | 469 return defer.ensureDeferred(self.connect(profile, password, options)) |
470 | 470 |
471 async def connect( | 471 async def connect( |
472 self, profile, password="", options=None, max_retries=C.XMPP_MAX_RETRIES): | 472 self, profile, password="", options=None, max_retries=C.XMPP_MAX_RETRIES): |
473 """Connect a profile (i.e. connect client.component to XMPP server) | 473 """Connect a profile (i.e. connect client.component to XMPP server) |
485 @raise exceptions.PasswordError: Profile password is wrong | 485 @raise exceptions.PasswordError: Profile password is wrong |
486 """ | 486 """ |
487 if options is None: | 487 if options is None: |
488 options = {} | 488 options = {} |
489 | 489 |
490 await self.memory.startSession(password, profile) | 490 await self.memory.start_session(password, profile) |
491 | 491 |
492 if self.isConnected(profile): | 492 if self.is_connected(profile): |
493 log.info(_("already connected !")) | 493 log.info(_("already connected !")) |
494 return True | 494 return True |
495 | 495 |
496 if self.memory.isComponent(profile): | 496 if self.memory.is_component(profile): |
497 await xmpp.SatXMPPComponent.startConnection(self, profile, max_retries) | 497 await xmpp.SatXMPPComponent.start_connection(self, profile, max_retries) |
498 else: | 498 else: |
499 await xmpp.SatXMPPClient.startConnection(self, profile, max_retries) | 499 await xmpp.SatXMPPClient.start_connection(self, profile, max_retries) |
500 | 500 |
501 return False | 501 return False |
502 | 502 |
503 def disconnect(self, profile_key): | 503 def disconnect(self, profile_key): |
504 """disconnect from jabber server""" | 504 """disconnect from jabber server""" |
505 # FIXME: client should not be deleted if only disconnected | 505 # FIXME: client should not be deleted if only disconnected |
506 # it shoud be deleted only when session is finished | 506 # it shoud be deleted only when session is finished |
507 if not self.isConnected(profile_key): | 507 if not self.is_connected(profile_key): |
508 # isConnected is checked here and not on client | 508 # is_connected is checked here and not on client |
509 # because client is deleted when session is ended | 509 # because client is deleted when session is ended |
510 log.info(_("not connected !")) | 510 log.info(_("not connected !")) |
511 return defer.succeed(None) | 511 return defer.succeed(None) |
512 client = self.getClient(profile_key) | 512 client = self.get_client(profile_key) |
513 return client.entityDisconnect() | 513 return client.entity_disconnect() |
514 | 514 |
515 def getFeatures(self, profile_key=C.PROF_KEY_NONE): | 515 def features_get(self, profile_key=C.PROF_KEY_NONE): |
516 """Get available features | 516 """Get available features |
517 | 517 |
518 Return list of activated plugins and plugin specific data | 518 Return list of activated plugins and plugin specific data |
519 @param profile_key: %(doc_profile_key)s | 519 @param profile_key: %(doc_profile_key)s |
520 C.PROF_KEY_NONE can be used to have general plugins data (i.e. not profile | 520 C.PROF_KEY_NONE can be used to have general plugins data (i.e. not profile |
526 If this method doesn't exists, an empty dict is returned. | 526 If this method doesn't exists, an empty dict is returned. |
527 """ | 527 """ |
528 try: | 528 try: |
529 # FIXME: there is no method yet to check profile session | 529 # FIXME: there is no method yet to check profile session |
530 # as soon as one is implemented, it should be used here | 530 # as soon as one is implemented, it should be used here |
531 self.getClient(profile_key) | 531 self.get_client(profile_key) |
532 except KeyError: | 532 except KeyError: |
533 log.warning("Requesting features for a profile outside a session") | 533 log.warning("Requesting features for a profile outside a session") |
534 profile_key = C.PROF_KEY_NONE | 534 profile_key = C.PROF_KEY_NONE |
535 except exceptions.ProfileNotSetError: | 535 except exceptions.ProfileNotSetError: |
536 pass | 536 pass |
537 | 537 |
538 features = [] | 538 features = [] |
539 for import_name, plugin in self.plugins.items(): | 539 for import_name, plugin in self.plugins.items(): |
540 try: | 540 try: |
541 features_d = utils.asDeferred(plugin.getFeatures, profile_key) | 541 features_d = utils.as_deferred(plugin.features_get, profile_key) |
542 except AttributeError: | 542 except AttributeError: |
543 features_d = defer.succeed({}) | 543 features_d = defer.succeed({}) |
544 features.append(features_d) | 544 features.append(features_d) |
545 | 545 |
546 d_list = defer.DeferredList(features) | 546 d_list = defer.DeferredList(features) |
547 | 547 |
548 def buildFeatures(result, import_names): | 548 def build_features(result, import_names): |
549 assert len(result) == len(import_names) | 549 assert len(result) == len(import_names) |
550 ret = {} | 550 ret = {} |
551 for name, (success, data) in zip(import_names, result): | 551 for name, (success, data) in zip(import_names, result): |
552 if success: | 552 if success: |
553 ret[name] = data | 553 ret[name] = data |
558 ) | 558 ) |
559 ) | 559 ) |
560 ret[name] = {} | 560 ret[name] = {} |
561 return ret | 561 return ret |
562 | 562 |
563 d_list.addCallback(buildFeatures, list(self.plugins.keys())) | 563 d_list.addCallback(build_features, list(self.plugins.keys())) |
564 return d_list | 564 return d_list |
565 | 565 |
566 def _contactGet(self, entity_jid_s, profile_key): | 566 def _contact_get(self, entity_jid_s, profile_key): |
567 client = self.getClient(profile_key) | 567 client = self.get_client(profile_key) |
568 entity_jid = jid.JID(entity_jid_s) | 568 entity_jid = jid.JID(entity_jid_s) |
569 return defer.ensureDeferred(self.getContact(client, entity_jid)) | 569 return defer.ensureDeferred(self.get_contact(client, entity_jid)) |
570 | 570 |
571 async def getContact(self, client, entity_jid): | 571 async def get_contact(self, client, entity_jid): |
572 # we want to be sure that roster has been received | 572 # we want to be sure that roster has been received |
573 await client.roster.got_roster | 573 await client.roster.got_roster |
574 item = client.roster.getItem(entity_jid) | 574 item = client.roster.get_item(entity_jid) |
575 if item is None: | 575 if item is None: |
576 raise exceptions.NotFound(f"{entity_jid} is not in roster!") | 576 raise exceptions.NotFound(f"{entity_jid} is not in roster!") |
577 return (client.roster.getAttributes(item), list(item.groups)) | 577 return (client.roster.get_attributes(item), list(item.groups)) |
578 | 578 |
579 def getContacts(self, profile_key): | 579 def contacts_get(self, profile_key): |
580 client = self.getClient(profile_key) | 580 client = self.get_client(profile_key) |
581 | 581 |
582 def got_roster(__): | 582 def got_roster(__): |
583 ret = [] | 583 ret = [] |
584 for item in client.roster.getItems(): # we get all items for client's roster | 584 for item in client.roster.get_items(): # we get all items for client's roster |
585 # and convert them to expected format | 585 # and convert them to expected format |
586 attr = client.roster.getAttributes(item) | 586 attr = client.roster.get_attributes(item) |
587 # we use full() and not userhost() because jid with resources are allowed | 587 # we use full() and not userhost() because jid with resources are allowed |
588 # in roster, even if it's not common. | 588 # in roster, even if it's not common. |
589 ret.append([item.entity.full(), attr, list(item.groups)]) | 589 ret.append([item.entity.full(), attr, list(item.groups)]) |
590 return ret | 590 return ret |
591 | 591 |
592 return client.roster.got_roster.addCallback(got_roster) | 592 return client.roster.got_roster.addCallback(got_roster) |
593 | 593 |
594 def getContactsFromGroup(self, group, profile_key): | 594 def contacts_get_from_group(self, group, profile_key): |
595 client = self.getClient(profile_key) | 595 client = self.get_client(profile_key) |
596 return [jid_.full() for jid_ in client.roster.getJidsFromGroup(group)] | 596 return [jid_.full() for jid_ in client.roster.get_jids_from_group(group)] |
597 | 597 |
598 def purgeEntity(self, profile): | 598 def purge_entity(self, profile): |
599 """Remove reference to a profile client/component and purge cache | 599 """Remove reference to a profile client/component and purge cache |
600 | 600 |
601 the garbage collector can then free the memory | 601 the garbage collector can then free the memory |
602 """ | 602 """ |
603 try: | 603 try: |
604 del self.profiles[profile] | 604 del self.profiles[profile] |
605 except KeyError: | 605 except KeyError: |
606 log.error(_("Trying to remove reference to a client not referenced")) | 606 log.error(_("Trying to remove reference to a client not referenced")) |
607 else: | 607 else: |
608 self.memory.purgeProfileSession(profile) | 608 self.memory.purge_profile_session(profile) |
609 | 609 |
610 def startService(self): | 610 def startService(self): |
611 self._init() | 611 self._init() |
612 log.info("Salut à toi ô mon frère !") | 612 log.info("Salut à toi ô mon frère !") |
613 | 613 |
614 def stopService(self): | 614 def stopService(self): |
615 log.info("Salut aussi à Rantanplan") | 615 log.info("Salut aussi à Rantanplan") |
616 return self.pluginsUnload() | 616 return self.plugins_unload() |
617 | 617 |
618 def run(self): | 618 def run(self): |
619 log.debug(_("running app")) | 619 log.debug(_("running app")) |
620 reactor.run() | 620 reactor.run() |
621 | 621 |
623 log.debug(_("stopping app")) | 623 log.debug(_("stopping app")) |
624 reactor.stop() | 624 reactor.stop() |
625 | 625 |
626 ## Misc methods ## | 626 ## Misc methods ## |
627 | 627 |
628 def getJidNStream(self, profile_key): | 628 def get_jid_n_stream(self, profile_key): |
629 """Convenient method to get jid and stream from profile key | 629 """Convenient method to get jid and stream from profile key |
630 @return: tuple (jid, xmlstream) from profile, can be None""" | 630 @return: tuple (jid, xmlstream) from profile, can be None""" |
631 # TODO: deprecate this method (getClient is enough) | 631 # TODO: deprecate this method (get_client is enough) |
632 profile = self.memory.getProfileName(profile_key) | 632 profile = self.memory.get_profile_name(profile_key) |
633 if not profile or not self.profiles[profile].isConnected(): | 633 if not profile or not self.profiles[profile].is_connected(): |
634 return (None, None) | 634 return (None, None) |
635 return (self.profiles[profile].jid, self.profiles[profile].xmlstream) | 635 return (self.profiles[profile].jid, self.profiles[profile].xmlstream) |
636 | 636 |
637 def getClient(self, profile_key: str) -> xmpp.SatXMPPClient: | 637 def get_client(self, profile_key: str) -> xmpp.SatXMPPClient: |
638 """Convenient method to get client from profile key | 638 """Convenient method to get client from profile key |
639 | 639 |
640 @return: the client | 640 @return: the client |
641 @raise exceptions.ProfileKeyUnknown: the profile or profile key doesn't exist | 641 @raise exceptions.ProfileKeyUnknown: the profile or profile key doesn't exist |
642 @raise exceptions.NotFound: client is not available | 642 @raise exceptions.NotFound: client is not available |
643 This happen if profile has not been used yet | 643 This happen if profile has not been used yet |
644 """ | 644 """ |
645 profile = self.memory.getProfileName(profile_key) | 645 profile = self.memory.get_profile_name(profile_key) |
646 if not profile: | 646 if not profile: |
647 raise exceptions.ProfileKeyUnknown | 647 raise exceptions.ProfileKeyUnknown |
648 try: | 648 try: |
649 return self.profiles[profile] | 649 return self.profiles[profile] |
650 except KeyError: | 650 except KeyError: |
651 raise exceptions.NotFound(profile_key) | 651 raise exceptions.NotFound(profile_key) |
652 | 652 |
653 def getClients(self, profile_key): | 653 def get_clients(self, profile_key): |
654 """Convenient method to get list of clients from profile key | 654 """Convenient method to get list of clients from profile key |
655 | 655 |
656 Manage list through profile_key like C.PROF_KEY_ALL | 656 Manage list through profile_key like C.PROF_KEY_ALL |
657 @param profile_key: %(doc_profile_key)s | 657 @param profile_key: %(doc_profile_key)s |
658 @return: list of clients | 658 @return: list of clients |
659 """ | 659 """ |
660 if not profile_key: | 660 if not profile_key: |
661 raise exceptions.DataError(_("profile_key must not be empty")) | 661 raise exceptions.DataError(_("profile_key must not be empty")) |
662 try: | 662 try: |
663 profile = self.memory.getProfileName(profile_key, True) | 663 profile = self.memory.get_profile_name(profile_key, True) |
664 except exceptions.ProfileUnknownError: | 664 except exceptions.ProfileUnknownError: |
665 return [] | 665 return [] |
666 if profile == C.PROF_KEY_ALL: | 666 if profile == C.PROF_KEY_ALL: |
667 return list(self.profiles.values()) | 667 return list(self.profiles.values()) |
668 elif profile[0] == "@": # only profile keys can start with "@" | 668 elif profile[0] == "@": # only profile keys can start with "@" |
669 raise exceptions.ProfileKeyUnknown | 669 raise exceptions.ProfileKeyUnknown |
670 return [self.profiles[profile]] | 670 return [self.profiles[profile]] |
671 | 671 |
672 def _getConfig(self, section, name): | 672 def _get_config(self, section, name): |
673 """Get the main configuration option | 673 """Get the main configuration option |
674 | 674 |
675 @param section: section of the config file (None or '' for DEFAULT) | 675 @param section: section of the config file (None or '' for DEFAULT) |
676 @param name: name of the option | 676 @param name: name of the option |
677 @return: unicode representation of the option | 677 @return: unicode representation of the option |
678 """ | 678 """ |
679 return str(self.memory.getConfig(section, name, "")) | 679 return str(self.memory.config_get(section, name, "")) |
680 | 680 |
681 def logErrback(self, failure_, msg=_("Unexpected error: {failure_}")): | 681 def log_errback(self, failure_, msg=_("Unexpected error: {failure_}")): |
682 """Generic errback logging | 682 """Generic errback logging |
683 | 683 |
684 @param msg(unicode): error message ("failure_" key will be use for format) | 684 @param msg(unicode): error message ("failure_" key will be use for format) |
685 can be used as last errback to show unexpected error | 685 can be used as last errback to show unexpected error |
686 """ | 686 """ |
687 log.error(msg.format(failure_=failure_)) | 687 log.error(msg.format(failure_=failure_)) |
688 return failure_ | 688 return failure_ |
689 | 689 |
690 # namespaces | 690 # namespaces |
691 | 691 |
692 def registerNamespace(self, short_name, namespace): | 692 def register_namespace(self, short_name, namespace): |
693 """associate a namespace to a short name""" | 693 """associate a namespace to a short name""" |
694 if short_name in self.ns_map: | 694 if short_name in self.ns_map: |
695 raise exceptions.ConflictError("this short name is already used") | 695 raise exceptions.ConflictError("this short name is already used") |
696 log.debug(f"registering namespace {short_name} => {namespace}") | 696 log.debug(f"registering namespace {short_name} => {namespace}") |
697 self.ns_map[short_name] = namespace | 697 self.ns_map[short_name] = namespace |
698 | 698 |
699 def getNamespaces(self): | 699 def get_namespaces(self): |
700 return self.ns_map | 700 return self.ns_map |
701 | 701 |
702 def getNamespace(self, short_name): | 702 def get_namespace(self, short_name): |
703 try: | 703 try: |
704 return self.ns_map[short_name] | 704 return self.ns_map[short_name] |
705 except KeyError: | 705 except KeyError: |
706 raise exceptions.NotFound("namespace {short_name} is not registered" | 706 raise exceptions.NotFound("namespace {short_name} is not registered" |
707 .format(short_name=short_name)) | 707 .format(short_name=short_name)) |
708 | 708 |
709 def getSessionInfos(self, profile_key): | 709 def get_session_infos(self, profile_key): |
710 """compile interesting data on current profile session""" | 710 """compile interesting data on current profile session""" |
711 client = self.getClient(profile_key) | 711 client = self.get_client(profile_key) |
712 data = { | 712 data = { |
713 "jid": client.jid.full(), | 713 "jid": client.jid.full(), |
714 "started": str(int(client.started)) | 714 "started": str(int(client.started)) |
715 } | 715 } |
716 return defer.succeed(data) | 716 return defer.succeed(data) |
717 | 717 |
718 def _getDevicesInfos(self, bare_jid, profile_key): | 718 def _get_devices_infos(self, bare_jid, profile_key): |
719 client = self.getClient(profile_key) | 719 client = self.get_client(profile_key) |
720 if not bare_jid: | 720 if not bare_jid: |
721 bare_jid = None | 721 bare_jid = None |
722 d = defer.ensureDeferred(self.getDevicesInfos(client, bare_jid)) | 722 d = defer.ensureDeferred(self.get_devices_infos(client, bare_jid)) |
723 d.addCallback(lambda data: data_format.serialise(data)) | 723 d.addCallback(lambda data: data_format.serialise(data)) |
724 return d | 724 return d |
725 | 725 |
726 async def getDevicesInfos(self, client, bare_jid=None): | 726 async def get_devices_infos(self, client, bare_jid=None): |
727 """compile data on an entity devices | 727 """compile data on an entity devices |
728 | 728 |
729 @param bare_jid(jid.JID, None): bare jid of entity to check | 729 @param bare_jid(jid.JID, None): bare jid of entity to check |
730 None to use client own jid | 730 None to use client own jid |
731 @return (list[dict]): list of data, one item per resource. | 731 @return (list[dict]): list of data, one item per resource. |
735 own_jid = client.jid.userhostJID() | 735 own_jid = client.jid.userhostJID() |
736 if bare_jid is None: | 736 if bare_jid is None: |
737 bare_jid = own_jid | 737 bare_jid = own_jid |
738 else: | 738 else: |
739 bare_jid = jid.JID(bare_jid) | 739 bare_jid = jid.JID(bare_jid) |
740 resources = self.memory.getAllResources(client, bare_jid) | 740 resources = self.memory.get_all_resources(client, bare_jid) |
741 if bare_jid == own_jid: | 741 if bare_jid == own_jid: |
742 # our own jid is not stored in memory's cache | 742 # our own jid is not stored in memory's cache |
743 resources.add(client.jid.resource) | 743 resources.add(client.jid.resource) |
744 ret_data = [] | 744 ret_data = [] |
745 for resource in resources: | 745 for resource in resources: |
746 res_jid = copy.copy(bare_jid) | 746 res_jid = copy.copy(bare_jid) |
747 res_jid.resource = resource | 747 res_jid.resource = resource |
748 cache_data = self.memory.getEntityData(client, res_jid) | 748 cache_data = self.memory.entity_data_get(client, res_jid) |
749 res_data = { | 749 res_data = { |
750 "resource": resource, | 750 "resource": resource, |
751 } | 751 } |
752 try: | 752 try: |
753 presence = cache_data['presence'] | 753 presence = cache_data['presence'] |
758 "show": presence.show, | 758 "show": presence.show, |
759 "priority": presence.priority, | 759 "priority": presence.priority, |
760 "statuses": presence.statuses, | 760 "statuses": presence.statuses, |
761 } | 761 } |
762 | 762 |
763 disco = await self.getDiscoInfos(client, res_jid) | 763 disco = await self.get_disco_infos(client, res_jid) |
764 | 764 |
765 for (category, type_), name in disco.identities.items(): | 765 for (category, type_), name in disco.identities.items(): |
766 identities = res_data.setdefault('identities', []) | 766 identities = res_data.setdefault('identities', []) |
767 identities.append({ | 767 identities.append({ |
768 "name": name, | 768 "name": name, |
774 | 774 |
775 return ret_data | 775 return ret_data |
776 | 776 |
777 # images | 777 # images |
778 | 778 |
779 def _imageCheck(self, path): | 779 def _image_check(self, path): |
780 report = image.check(self, path) | 780 report = image.check(self, path) |
781 return data_format.serialise(report) | 781 return data_format.serialise(report) |
782 | 782 |
783 def _imageResize(self, path, width, height): | 783 def _image_resize(self, path, width, height): |
784 d = image.resize(path, (width, height)) | 784 d = image.resize(path, (width, height)) |
785 d.addCallback(lambda new_image_path: str(new_image_path)) | 785 d.addCallback(lambda new_image_path: str(new_image_path)) |
786 return d | 786 return d |
787 | 787 |
788 def _imageGeneratePreview(self, path, profile_key): | 788 def _image_generate_preview(self, path, profile_key): |
789 client = self.getClient(profile_key) | 789 client = self.get_client(profile_key) |
790 d = defer.ensureDeferred(self.imageGeneratePreview(client, Path(path))) | 790 d = defer.ensureDeferred(self.image_generate_preview(client, Path(path))) |
791 d.addCallback(lambda preview_path: str(preview_path)) | 791 d.addCallback(lambda preview_path: str(preview_path)) |
792 return d | 792 return d |
793 | 793 |
794 async def imageGeneratePreview(self, client, path): | 794 async def image_generate_preview(self, client, path): |
795 """Helper method to generate in cache a preview of an image | 795 """Helper method to generate in cache a preview of an image |
796 | 796 |
797 @param path(Path): path to the image | 797 @param path(Path): path to the image |
798 @return (Path): path to the generated preview | 798 @return (Path): path to the generated preview |
799 """ | 799 """ |
805 else: | 805 else: |
806 # we use hash as id, to re-use potentially existing preview | 806 # we use hash as id, to re-use potentially existing preview |
807 path_hash = hashlib.sha256(str(path).encode()).hexdigest() | 807 path_hash = hashlib.sha256(str(path).encode()).hexdigest() |
808 uid = f"{path.stem}_{path_hash}_preview" | 808 uid = f"{path.stem}_{path_hash}_preview" |
809 filename = f"{uid}{path.suffix.lower()}" | 809 filename = f"{uid}{path.suffix.lower()}" |
810 metadata = client.cache.getMetadata(uid=uid) | 810 metadata = client.cache.get_metadata(uid=uid) |
811 if metadata is not None: | 811 if metadata is not None: |
812 preview_path = metadata['path'] | 812 preview_path = metadata['path'] |
813 else: | 813 else: |
814 with client.cache.cacheData( | 814 with client.cache.cache_data( |
815 source='HOST_PREVIEW', | 815 source='HOST_PREVIEW', |
816 uid=uid, | 816 uid=uid, |
817 filename=filename) as cache_f: | 817 filename=filename) as cache_f: |
818 | 818 |
819 preview_path = await image.resize( | 819 preview_path = await image.resize( |
822 dest=cache_f | 822 dest=cache_f |
823 ) | 823 ) |
824 | 824 |
825 return preview_path | 825 return preview_path |
826 | 826 |
827 def _imageConvert(self, source, dest, extra, profile_key): | 827 def _image_convert(self, source, dest, extra, profile_key): |
828 client = self.getClient(profile_key) if profile_key else None | 828 client = self.get_client(profile_key) if profile_key else None |
829 source = Path(source) | 829 source = Path(source) |
830 dest = None if not dest else Path(dest) | 830 dest = None if not dest else Path(dest) |
831 extra = data_format.deserialise(extra) | 831 extra = data_format.deserialise(extra) |
832 d = defer.ensureDeferred(self.imageConvert(client, source, dest, extra)) | 832 d = defer.ensureDeferred(self.image_convert(client, source, dest, extra)) |
833 d.addCallback(lambda dest_path: str(dest_path)) | 833 d.addCallback(lambda dest_path: str(dest_path)) |
834 return d | 834 return d |
835 | 835 |
836 async def imageConvert(self, client, source, dest=None, extra=None): | 836 async def image_convert(self, client, source, dest=None, extra=None): |
837 """Helper method to convert an image from one format to an other | 837 """Helper method to convert an image from one format to an other |
838 | 838 |
839 @param client(SatClient, None): client to use for caching | 839 @param client(SatClient, None): client to use for caching |
840 this parameter is only used if dest is None | 840 this parameter is only used if dest is None |
841 if client is None, common cache will be used insted of profile cache | 841 if client is None, common cache will be used insted of profile cache |
859 filename = f"{uid}.png" | 859 filename = f"{uid}.png" |
860 if client is None: | 860 if client is None: |
861 cache = self.common_cache | 861 cache = self.common_cache |
862 else: | 862 else: |
863 cache = client.cache | 863 cache = client.cache |
864 metadata = cache.getMetadata(uid=uid) | 864 metadata = cache.get_metadata(uid=uid) |
865 if metadata is not None: | 865 if metadata is not None: |
866 # there is already a conversion for this image in cache | 866 # there is already a conversion for this image in cache |
867 return metadata['path'] | 867 return metadata['path'] |
868 else: | 868 else: |
869 with cache.cacheData( | 869 with cache.cache_data( |
870 source='HOST_IMAGE_CONVERT', | 870 source='HOST_IMAGE_CONVERT', |
871 uid=uid, | 871 uid=uid, |
872 filename=filename) as cache_f: | 872 filename=filename) as cache_f: |
873 | 873 |
874 converted_path = await image.convert( | 874 converted_path = await image.convert( |
898 @param dir_name: name of the main path directory | 898 @param dir_name: name of the main path directory |
899 @param *extra_path: extra path element(s) to use | 899 @param *extra_path: extra path element(s) to use |
900 @param component: if True, path will be prefixed with C.COMPONENTS_DIR | 900 @param component: if True, path will be prefixed with C.COMPONENTS_DIR |
901 @return: path | 901 @return: path |
902 """ | 902 """ |
903 local_dir = self.memory.getConfig("", "local_dir") | 903 local_dir = self.memory.config_get("", "local_dir") |
904 if not local_dir: | 904 if not local_dir: |
905 raise exceptions.InternalError("local_dir must be set") | 905 raise exceptions.InternalError("local_dir must be set") |
906 path_elts = [] | 906 path_elts = [] |
907 if component: | 907 if component: |
908 path_elts.append(C.COMPONENTS_DIR) | 908 path_elts.append(C.COMPONENTS_DIR) |
909 path_elts.append(regex.pathEscape(dir_name)) | 909 path_elts.append(regex.path_escape(dir_name)) |
910 if extra_path: | 910 if extra_path: |
911 path_elts.extend([regex.pathEscape(p) for p in extra_path]) | 911 path_elts.extend([regex.path_escape(p) for p in extra_path]) |
912 if client is not None: | 912 if client is not None: |
913 path_elts.append(regex.pathEscape(client.profile)) | 913 path_elts.append(regex.path_escape(client.profile)) |
914 local_path = Path(*path_elts) | 914 local_path = Path(*path_elts) |
915 local_path.mkdir(0o700, parents=True, exist_ok=True) | 915 local_path.mkdir(0o700, parents=True, exist_ok=True) |
916 return local_path | 916 return local_path |
917 | 917 |
918 ## Client management ## | 918 ## Client management ## |
919 | 919 |
920 def setParam(self, name, value, category, security_limit, profile_key): | 920 def param_set(self, name, value, category, security_limit, profile_key): |
921 """set wanted paramater and notice observers""" | 921 """set wanted paramater and notice observers""" |
922 self.memory.setParam(name, value, category, security_limit, profile_key) | 922 self.memory.param_set(name, value, category, security_limit, profile_key) |
923 | 923 |
924 def isConnected(self, profile_key): | 924 def is_connected(self, profile_key): |
925 """Return connection status of profile | 925 """Return connection status of profile |
926 | 926 |
927 @param profile_key: key_word or profile name to determine profile name | 927 @param profile_key: key_word or profile name to determine profile name |
928 @return: True if connected | 928 @return: True if connected |
929 """ | 929 """ |
930 profile = self.memory.getProfileName(profile_key) | 930 profile = self.memory.get_profile_name(profile_key) |
931 if not profile: | 931 if not profile: |
932 log.error(_("asking connection status for a non-existant profile")) | 932 log.error(_("asking connection status for a non-existant profile")) |
933 raise exceptions.ProfileUnknownError(profile_key) | 933 raise exceptions.ProfileUnknownError(profile_key) |
934 if profile not in self.profiles: | 934 if profile not in self.profiles: |
935 return False | 935 return False |
936 return self.profiles[profile].isConnected() | 936 return self.profiles[profile].is_connected() |
937 | 937 |
938 ## Encryption ## | 938 ## Encryption ## |
939 | 939 |
940 def registerEncryptionPlugin(self, *args, **kwargs): | 940 def register_encryption_plugin(self, *args, **kwargs): |
941 return encryption.EncryptionHandler.registerPlugin(*args, **kwargs) | 941 return encryption.EncryptionHandler.register_plugin(*args, **kwargs) |
942 | 942 |
943 def _messageEncryptionStart(self, to_jid_s, namespace, replace=False, | 943 def _message_encryption_start(self, to_jid_s, namespace, replace=False, |
944 profile_key=C.PROF_KEY_NONE): | 944 profile_key=C.PROF_KEY_NONE): |
945 client = self.getClient(profile_key) | 945 client = self.get_client(profile_key) |
946 to_jid = jid.JID(to_jid_s) | 946 to_jid = jid.JID(to_jid_s) |
947 return defer.ensureDeferred( | 947 return defer.ensureDeferred( |
948 client.encryption.start(to_jid, namespace or None, replace)) | 948 client.encryption.start(to_jid, namespace or None, replace)) |
949 | 949 |
950 def _messageEncryptionStop(self, to_jid_s, profile_key=C.PROF_KEY_NONE): | 950 def _message_encryption_stop(self, to_jid_s, profile_key=C.PROF_KEY_NONE): |
951 client = self.getClient(profile_key) | 951 client = self.get_client(profile_key) |
952 to_jid = jid.JID(to_jid_s) | 952 to_jid = jid.JID(to_jid_s) |
953 return defer.ensureDeferred( | 953 return defer.ensureDeferred( |
954 client.encryption.stop(to_jid)) | 954 client.encryption.stop(to_jid)) |
955 | 955 |
956 def _messageEncryptionGet(self, to_jid_s, profile_key=C.PROF_KEY_NONE): | 956 def _message_encryption_get(self, to_jid_s, profile_key=C.PROF_KEY_NONE): |
957 client = self.getClient(profile_key) | 957 client = self.get_client(profile_key) |
958 to_jid = jid.JID(to_jid_s) | 958 to_jid = jid.JID(to_jid_s) |
959 session_data = client.encryption.getSession(to_jid) | 959 session_data = client.encryption.getSession(to_jid) |
960 return client.encryption.getBridgeData(session_data) | 960 return client.encryption.get_bridge_data(session_data) |
961 | 961 |
962 def _encryptionNamespaceGet(self, name): | 962 def _encryption_namespace_get(self, name): |
963 return encryption.EncryptionHandler.getNSFromName(name) | 963 return encryption.EncryptionHandler.get_ns_from_name(name) |
964 | 964 |
965 def _encryptionPluginsGet(self): | 965 def _encryption_plugins_get(self): |
966 plugins = encryption.EncryptionHandler.getPlugins() | 966 plugins = encryption.EncryptionHandler.getPlugins() |
967 ret = [] | 967 ret = [] |
968 for p in plugins: | 968 for p in plugins: |
969 ret.append({ | 969 ret.append({ |
970 "name": p.name, | 970 "name": p.name, |
972 "priority": p.priority, | 972 "priority": p.priority, |
973 "directed": p.directed, | 973 "directed": p.directed, |
974 }) | 974 }) |
975 return data_format.serialise(ret) | 975 return data_format.serialise(ret) |
976 | 976 |
977 def _encryptionTrustUIGet(self, to_jid_s, namespace, profile_key): | 977 def _encryption_trust_ui_get(self, to_jid_s, namespace, profile_key): |
978 client = self.getClient(profile_key) | 978 client = self.get_client(profile_key) |
979 to_jid = jid.JID(to_jid_s) | 979 to_jid = jid.JID(to_jid_s) |
980 d = defer.ensureDeferred( | 980 d = defer.ensureDeferred( |
981 client.encryption.getTrustUI(to_jid, namespace=namespace or None)) | 981 client.encryption.get_trust_ui(to_jid, namespace=namespace or None)) |
982 d.addCallback(lambda xmlui: xmlui.toXml()) | 982 d.addCallback(lambda xmlui: xmlui.toXml()) |
983 return d | 983 return d |
984 | 984 |
985 ## XMPP methods ## | 985 ## XMPP methods ## |
986 | 986 |
987 def _messageSend( | 987 def _message_send( |
988 self, to_jid_s, message, subject=None, mess_type="auto", extra_s="", | 988 self, to_jid_s, message, subject=None, mess_type="auto", extra_s="", |
989 profile_key=C.PROF_KEY_NONE): | 989 profile_key=C.PROF_KEY_NONE): |
990 client = self.getClient(profile_key) | 990 client = self.get_client(profile_key) |
991 to_jid = jid.JID(to_jid_s) | 991 to_jid = jid.JID(to_jid_s) |
992 return client.sendMessage( | 992 return client.sendMessage( |
993 to_jid, | 993 to_jid, |
994 message, | 994 message, |
995 subject, | 995 subject, |
996 mess_type, | 996 mess_type, |
997 data_format.deserialise(extra_s) | 997 data_format.deserialise(extra_s) |
998 ) | 998 ) |
999 | 999 |
1000 def _setPresence(self, to="", show="", statuses=None, profile_key=C.PROF_KEY_NONE): | 1000 def _set_presence(self, to="", show="", statuses=None, profile_key=C.PROF_KEY_NONE): |
1001 return self.setPresence(jid.JID(to) if to else None, show, statuses, profile_key) | 1001 return self.presence_set(jid.JID(to) if to else None, show, statuses, profile_key) |
1002 | 1002 |
1003 def setPresence(self, to_jid=None, show="", statuses=None, | 1003 def presence_set(self, to_jid=None, show="", statuses=None, |
1004 profile_key=C.PROF_KEY_NONE): | 1004 profile_key=C.PROF_KEY_NONE): |
1005 """Send our presence information""" | 1005 """Send our presence information""" |
1006 if statuses is None: | 1006 if statuses is None: |
1007 statuses = {} | 1007 statuses = {} |
1008 profile = self.memory.getProfileName(profile_key) | 1008 profile = self.memory.get_profile_name(profile_key) |
1009 assert profile | 1009 assert profile |
1010 priority = int( | 1010 priority = int( |
1011 self.memory.getParamA("Priority", "Connection", profile_key=profile) | 1011 self.memory.param_get_a("Priority", "Connection", profile_key=profile) |
1012 ) | 1012 ) |
1013 self.profiles[profile].presence.available(to_jid, show, statuses, priority) | 1013 self.profiles[profile].presence.available(to_jid, show, statuses, priority) |
1014 # XXX: FIXME: temporary fix to work around openfire 3.7.0 bug (presence is not | 1014 # XXX: FIXME: temporary fix to work around openfire 3.7.0 bug (presence is not |
1015 # broadcasted to generating resource) | 1015 # broadcasted to generating resource) |
1016 if "" in statuses: | 1016 if "" in statuses: |
1017 statuses[C.PRESENCE_STATUSES_DEFAULT] = statuses.pop("") | 1017 statuses[C.PRESENCE_STATUSES_DEFAULT] = statuses.pop("") |
1018 self.bridge.presenceUpdate( | 1018 self.bridge.presence_update( |
1019 self.profiles[profile].jid.full(), show, int(priority), statuses, profile | 1019 self.profiles[profile].jid.full(), show, int(priority), statuses, profile |
1020 ) | 1020 ) |
1021 | 1021 |
1022 def subscription(self, subs_type, raw_jid, profile_key): | 1022 def subscription(self, subs_type, raw_jid, profile_key): |
1023 """Called to manage subscription | 1023 """Called to manage subscription |
1024 @param subs_type: subsciption type (cf RFC 3921) | 1024 @param subs_type: subsciption type (cf RFC 3921) |
1025 @param raw_jid: unicode entity's jid | 1025 @param raw_jid: unicode entity's jid |
1026 @param profile_key: profile""" | 1026 @param profile_key: profile""" |
1027 profile = self.memory.getProfileName(profile_key) | 1027 profile = self.memory.get_profile_name(profile_key) |
1028 assert profile | 1028 assert profile |
1029 to_jid = jid.JID(raw_jid) | 1029 to_jid = jid.JID(raw_jid) |
1030 log.debug( | 1030 log.debug( |
1031 _("subsciption request [%(subs_type)s] for %(jid)s") | 1031 _("subsciption request [%(subs_type)s] for %(jid)s") |
1032 % {"subs_type": subs_type, "jid": to_jid.full()} | 1032 % {"subs_type": subs_type, "jid": to_jid.full()} |
1038 elif subs_type == "unsubscribe": | 1038 elif subs_type == "unsubscribe": |
1039 self.profiles[profile].presence.unsubscribe(to_jid) | 1039 self.profiles[profile].presence.unsubscribe(to_jid) |
1040 elif subs_type == "unsubscribed": | 1040 elif subs_type == "unsubscribed": |
1041 self.profiles[profile].presence.unsubscribed(to_jid) | 1041 self.profiles[profile].presence.unsubscribed(to_jid) |
1042 | 1042 |
1043 def _addContact(self, to_jid_s, profile_key): | 1043 def _add_contact(self, to_jid_s, profile_key): |
1044 return self.addContact(jid.JID(to_jid_s), profile_key) | 1044 return self.contact_add(jid.JID(to_jid_s), profile_key) |
1045 | 1045 |
1046 def addContact(self, to_jid, profile_key): | 1046 def contact_add(self, to_jid, profile_key): |
1047 """Add a contact in roster list""" | 1047 """Add a contact in roster list""" |
1048 profile = self.memory.getProfileName(profile_key) | 1048 profile = self.memory.get_profile_name(profile_key) |
1049 assert profile | 1049 assert profile |
1050 # presence is sufficient, as a roster push will be sent according to | 1050 # presence is sufficient, as a roster push will be sent according to |
1051 # RFC 6121 §3.1.2 | 1051 # RFC 6121 §3.1.2 |
1052 self.profiles[profile].presence.subscribe(to_jid) | 1052 self.profiles[profile].presence.subscribe(to_jid) |
1053 | 1053 |
1054 def _updateContact(self, to_jid_s, name, groups, profile_key): | 1054 def _update_contact(self, to_jid_s, name, groups, profile_key): |
1055 client = self.getClient(profile_key) | 1055 client = self.get_client(profile_key) |
1056 return self.updateContact(client, jid.JID(to_jid_s), name, groups) | 1056 return self.contact_update(client, jid.JID(to_jid_s), name, groups) |
1057 | 1057 |
1058 def updateContact(self, client, to_jid, name, groups): | 1058 def contact_update(self, client, to_jid, name, groups): |
1059 """update a contact in roster list""" | 1059 """update a contact in roster list""" |
1060 roster_item = RosterItem(to_jid) | 1060 roster_item = RosterItem(to_jid) |
1061 roster_item.name = name or u'' | 1061 roster_item.name = name or u'' |
1062 roster_item.groups = set(groups) | 1062 roster_item.groups = set(groups) |
1063 if not self.trigger.point("roster_update", client, roster_item): | 1063 if not self.trigger.point("roster_update", client, roster_item): |
1064 return | 1064 return |
1065 return client.roster.setItem(roster_item) | 1065 return client.roster.setItem(roster_item) |
1066 | 1066 |
1067 def _delContact(self, to_jid_s, profile_key): | 1067 def _del_contact(self, to_jid_s, profile_key): |
1068 return self.delContact(jid.JID(to_jid_s), profile_key) | 1068 return self.contact_del(jid.JID(to_jid_s), profile_key) |
1069 | 1069 |
1070 def delContact(self, to_jid, profile_key): | 1070 def contact_del(self, to_jid, profile_key): |
1071 """Remove contact from roster list""" | 1071 """Remove contact from roster list""" |
1072 profile = self.memory.getProfileName(profile_key) | 1072 profile = self.memory.get_profile_name(profile_key) |
1073 assert profile | 1073 assert profile |
1074 self.profiles[profile].presence.unsubscribe(to_jid) # is not asynchronous | 1074 self.profiles[profile].presence.unsubscribe(to_jid) # is not asynchronous |
1075 return self.profiles[profile].roster.removeItem(to_jid) | 1075 return self.profiles[profile].roster.removeItem(to_jid) |
1076 | 1076 |
1077 def _rosterResync(self, profile_key): | 1077 def _roster_resync(self, profile_key): |
1078 client = self.getClient(profile_key) | 1078 client = self.get_client(profile_key) |
1079 return client.roster.resync() | 1079 return client.roster.resync() |
1080 | 1080 |
1081 ## Discovery ## | 1081 ## Discovery ## |
1082 # discovery methods are shortcuts to self.memory.disco | 1082 # discovery methods are shortcuts to self.memory.disco |
1083 # the main difference with client.disco is that self.memory.disco manage cache | 1083 # the main difference with client.disco is that self.memory.disco manage cache |
1084 | 1084 |
1085 def hasFeature(self, *args, **kwargs): | 1085 def hasFeature(self, *args, **kwargs): |
1086 return self.memory.disco.hasFeature(*args, **kwargs) | 1086 return self.memory.disco.hasFeature(*args, **kwargs) |
1087 | 1087 |
1088 def checkFeature(self, *args, **kwargs): | 1088 def check_feature(self, *args, **kwargs): |
1089 return self.memory.disco.checkFeature(*args, **kwargs) | 1089 return self.memory.disco.check_feature(*args, **kwargs) |
1090 | 1090 |
1091 def checkFeatures(self, *args, **kwargs): | 1091 def check_features(self, *args, **kwargs): |
1092 return self.memory.disco.checkFeatures(*args, **kwargs) | 1092 return self.memory.disco.check_features(*args, **kwargs) |
1093 | 1093 |
1094 def hasIdentity(self, *args, **kwargs): | 1094 def has_identity(self, *args, **kwargs): |
1095 return self.memory.disco.hasIdentity(*args, **kwargs) | 1095 return self.memory.disco.has_identity(*args, **kwargs) |
1096 | 1096 |
1097 def getDiscoInfos(self, *args, **kwargs): | 1097 def get_disco_infos(self, *args, **kwargs): |
1098 return self.memory.disco.getInfos(*args, **kwargs) | 1098 return self.memory.disco.get_infos(*args, **kwargs) |
1099 | 1099 |
1100 def getDiscoItems(self, *args, **kwargs): | 1100 def getDiscoItems(self, *args, **kwargs): |
1101 return self.memory.disco.getItems(*args, **kwargs) | 1101 return self.memory.disco.get_items(*args, **kwargs) |
1102 | 1102 |
1103 def findServiceEntity(self, *args, **kwargs): | 1103 def find_service_entity(self, *args, **kwargs): |
1104 return self.memory.disco.findServiceEntity(*args, **kwargs) | 1104 return self.memory.disco.find_service_entity(*args, **kwargs) |
1105 | 1105 |
1106 def findServiceEntities(self, *args, **kwargs): | 1106 def find_service_entities(self, *args, **kwargs): |
1107 return self.memory.disco.findServiceEntities(*args, **kwargs) | 1107 return self.memory.disco.find_service_entities(*args, **kwargs) |
1108 | 1108 |
1109 def findFeaturesSet(self, *args, **kwargs): | 1109 def find_features_set(self, *args, **kwargs): |
1110 return self.memory.disco.findFeaturesSet(*args, **kwargs) | 1110 return self.memory.disco.find_features_set(*args, **kwargs) |
1111 | 1111 |
1112 def _findByFeatures(self, namespaces, identities, bare_jids, service, roster, own_jid, | 1112 def _find_by_features(self, namespaces, identities, bare_jids, service, roster, own_jid, |
1113 local_device, profile_key): | 1113 local_device, profile_key): |
1114 client = self.getClient(profile_key) | 1114 client = self.get_client(profile_key) |
1115 identities = [tuple(i) for i in identities] if identities else None | 1115 identities = [tuple(i) for i in identities] if identities else None |
1116 return defer.ensureDeferred(self.findByFeatures( | 1116 return defer.ensureDeferred(self.find_by_features( |
1117 client, namespaces, identities, bare_jids, service, roster, own_jid, | 1117 client, namespaces, identities, bare_jids, service, roster, own_jid, |
1118 local_device)) | 1118 local_device)) |
1119 | 1119 |
1120 async def findByFeatures( | 1120 async def find_by_features( |
1121 self, | 1121 self, |
1122 client: xmpp.SatXMPPEntity, | 1122 client: xmpp.SatXMPPEntity, |
1123 namespaces: List[str], | 1123 namespaces: List[str], |
1124 identities: Optional[List[Tuple[str, str]]]=None, | 1124 identities: Optional[List[Tuple[str, str]]]=None, |
1125 bare_jids: bool=False, | 1125 bare_jids: bool=False, |
1162 ) | 1162 ) |
1163 found_service = {} | 1163 found_service = {} |
1164 found_own = {} | 1164 found_own = {} |
1165 found_roster = {} | 1165 found_roster = {} |
1166 if service: | 1166 if service: |
1167 services_jids = await self.findFeaturesSet(client, namespaces) | 1167 services_jids = await self.find_features_set(client, namespaces) |
1168 services_jids = list(services_jids) # we need a list to map results below | 1168 services_jids = list(services_jids) # we need a list to map results below |
1169 services_infos = await defer.DeferredList( | 1169 services_infos = await defer.DeferredList( |
1170 [self.getDiscoInfos(client, service_jid) for service_jid in services_jids] | 1170 [self.get_disco_infos(client, service_jid) for service_jid in services_jids] |
1171 ) | 1171 ) |
1172 | 1172 |
1173 for idx, (success, infos) in enumerate(services_infos): | 1173 for idx, (success, infos) in enumerate(services_infos): |
1174 service_jid = services_jids[idx] | 1174 service_jid = services_jids[idx] |
1175 if not success: | 1175 if not success: |
1188 | 1188 |
1189 to_find = [] | 1189 to_find = [] |
1190 if own_jid: | 1190 if own_jid: |
1191 to_find.append((found_own, [client.jid.userhostJID()])) | 1191 to_find.append((found_own, [client.jid.userhostJID()])) |
1192 if roster: | 1192 if roster: |
1193 to_find.append((found_roster, client.roster.getJids())) | 1193 to_find.append((found_roster, client.roster.get_jids())) |
1194 | 1194 |
1195 for found, jids in to_find: | 1195 for found, jids in to_find: |
1196 full_jids = [] | 1196 full_jids = [] |
1197 disco_defers = [] | 1197 disco_defers = [] |
1198 | 1198 |
1204 else: | 1204 else: |
1205 if bare_jids: | 1205 if bare_jids: |
1206 resources = [None] | 1206 resources = [None] |
1207 else: | 1207 else: |
1208 try: | 1208 try: |
1209 resources = self.memory.getAvailableResources(client, jid_) | 1209 resources = self.memory.get_available_resources(client, jid_) |
1210 except exceptions.UnknownEntityError: | 1210 except exceptions.UnknownEntityError: |
1211 continue | 1211 continue |
1212 if not resources and jid_ == client.jid.userhostJID() and own_jid: | 1212 if not resources and jid_ == client.jid.userhostJID() and own_jid: |
1213 # small hack to avoid missing our own resource when this | 1213 # small hack to avoid missing our own resource when this |
1214 # method is called at the very beginning of the session | 1214 # method is called at the very beginning of the session |
1218 full_jid = jid.JID(tuple=(jid_.user, jid_.host, resource)) | 1218 full_jid = jid.JID(tuple=(jid_.user, jid_.host, resource)) |
1219 if full_jid == client.jid and not local_device: | 1219 if full_jid == client.jid and not local_device: |
1220 continue | 1220 continue |
1221 full_jids.append(full_jid) | 1221 full_jids.append(full_jid) |
1222 | 1222 |
1223 disco_defers.append(self.getDiscoInfos(client, full_jid)) | 1223 disco_defers.append(self.get_disco_infos(client, full_jid)) |
1224 | 1224 |
1225 d_list = defer.DeferredList(disco_defers) | 1225 d_list = defer.DeferredList(disco_defers) |
1226 # XXX: 10 seconds may be too low for slow connections (e.g. mobiles) | 1226 # XXX: 10 seconds may be too low for slow connections (e.g. mobiles) |
1227 # but for discovery, that's also the time the user will wait the first time | 1227 # but for discovery, that's also the time the user will wait the first time |
1228 # before seing the page, if something goes wrong. | 1228 # before seing the page, if something goes wrong. |
1249 | 1249 |
1250 return (found_service, found_own, found_roster) | 1250 return (found_service, found_own, found_roster) |
1251 | 1251 |
1252 ## Generic HMI ## | 1252 ## Generic HMI ## |
1253 | 1253 |
1254 def _killAction(self, keep_id, client): | 1254 def _kill_action(self, keep_id, client): |
1255 log.debug("Killing action {} for timeout".format(keep_id)) | 1255 log.debug("Killing action {} for timeout".format(keep_id)) |
1256 client.actions[keep_id] | 1256 client.actions[keep_id] |
1257 | 1257 |
1258 def actionNew( | 1258 def action_new( |
1259 self, | 1259 self, |
1260 action_data, | 1260 action_data, |
1261 security_limit=C.NO_SECURITY_LIMIT, | 1261 security_limit=C.NO_SECURITY_LIMIT, |
1262 keep_id=None, | 1262 keep_id=None, |
1263 profile=C.PROF_KEY_NONE, | 1263 profile=C.PROF_KEY_NONE, |
1264 ): | 1264 ): |
1265 """Shortcut to bridge.actionNew which generate and id and keep for retrieval | 1265 """Shortcut to bridge.action_new which generate and id and keep for retrieval |
1266 | 1266 |
1267 @param action_data(dict): action data (see bridge documentation) | 1267 @param action_data(dict): action data (see bridge documentation) |
1268 @param security_limit: %(doc_security_limit)s | 1268 @param security_limit: %(doc_security_limit)s |
1269 @param keep_id(None, unicode): if not None, used to keep action for differed | 1269 @param keep_id(None, unicode): if not None, used to keep action for differed |
1270 retrieval. Must be set to the callback_id. | 1270 retrieval. Must be set to the callback_id. |
1271 Action will be deleted after 30 min. | 1271 Action will be deleted after 30 min. |
1272 @param profile: %(doc_profile)s | 1272 @param profile: %(doc_profile)s |
1273 """ | 1273 """ |
1274 id_ = str(uuid.uuid4()) | 1274 id_ = str(uuid.uuid4()) |
1275 if keep_id is not None: | 1275 if keep_id is not None: |
1276 client = self.getClient(profile) | 1276 client = self.get_client(profile) |
1277 action_timer = reactor.callLater(60 * 30, self._killAction, keep_id, client) | 1277 action_timer = reactor.callLater(60 * 30, self._kill_action, keep_id, client) |
1278 client.actions[keep_id] = (action_data, id_, security_limit, action_timer) | 1278 client.actions[keep_id] = (action_data, id_, security_limit, action_timer) |
1279 | 1279 |
1280 self.bridge.actionNew(action_data, id_, security_limit, profile) | 1280 self.bridge.action_new(action_data, id_, security_limit, profile) |
1281 | 1281 |
1282 def actionsGet(self, profile): | 1282 def actions_get(self, profile): |
1283 """Return current non answered actions | 1283 """Return current non answered actions |
1284 | 1284 |
1285 @param profile: %(doc_profile)s | 1285 @param profile: %(doc_profile)s |
1286 """ | 1286 """ |
1287 client = self.getClient(profile) | 1287 client = self.get_client(profile) |
1288 return [action_tuple[:-1] for action_tuple in client.actions.values()] | 1288 return [action_tuple[:-1] for action_tuple in client.actions.values()] |
1289 | 1289 |
1290 def registerProgressCb( | 1290 def register_progress_cb( |
1291 self, progress_id, callback, metadata=None, profile=C.PROF_KEY_NONE | 1291 self, progress_id, callback, metadata=None, profile=C.PROF_KEY_NONE |
1292 ): | 1292 ): |
1293 """Register a callback called when progress is requested for id""" | 1293 """Register a callback called when progress is requested for id""" |
1294 if metadata is None: | 1294 if metadata is None: |
1295 metadata = {} | 1295 metadata = {} |
1296 client = self.getClient(profile) | 1296 client = self.get_client(profile) |
1297 if progress_id in client._progress_cb: | 1297 if progress_id in client._progress_cb: |
1298 raise exceptions.ConflictError("Progress ID is not unique !") | 1298 raise exceptions.ConflictError("Progress ID is not unique !") |
1299 client._progress_cb[progress_id] = (callback, metadata) | 1299 client._progress_cb[progress_id] = (callback, metadata) |
1300 | 1300 |
1301 def removeProgressCb(self, progress_id, profile): | 1301 def remove_progress_cb(self, progress_id, profile): |
1302 """Remove a progress callback""" | 1302 """Remove a progress callback""" |
1303 client = self.getClient(profile) | 1303 client = self.get_client(profile) |
1304 try: | 1304 try: |
1305 del client._progress_cb[progress_id] | 1305 del client._progress_cb[progress_id] |
1306 except KeyError: | 1306 except KeyError: |
1307 log.error(_("Trying to remove an unknow progress callback")) | 1307 log.error(_("Trying to remove an unknow progress callback")) |
1308 | 1308 |
1309 def _progressGet(self, progress_id, profile): | 1309 def _progress_get(self, progress_id, profile): |
1310 data = self.progressGet(progress_id, profile) | 1310 data = self.progress_get(progress_id, profile) |
1311 return {k: str(v) for k, v in data.items()} | 1311 return {k: str(v) for k, v in data.items()} |
1312 | 1312 |
1313 def progressGet(self, progress_id, profile): | 1313 def progress_get(self, progress_id, profile): |
1314 """Return a dict with progress information | 1314 """Return a dict with progress information |
1315 | 1315 |
1316 @param progress_id(unicode): unique id of the progressing element | 1316 @param progress_id(unicode): unique id of the progressing element |
1317 @param profile: %(doc_profile)s | 1317 @param profile: %(doc_profile)s |
1318 @return (dict): data with the following keys: | 1318 @return (dict): data with the following keys: |
1319 'position' (int): current possition | 1319 'position' (int): current possition |
1320 'size' (int): end_position | 1320 'size' (int): end_position |
1321 if id doesn't exists (may be a finished progression), and empty dict is | 1321 if id doesn't exists (may be a finished progression), and empty dict is |
1322 returned | 1322 returned |
1323 """ | 1323 """ |
1324 client = self.getClient(profile) | 1324 client = self.get_client(profile) |
1325 try: | 1325 try: |
1326 data = client._progress_cb[progress_id][0](progress_id, profile) | 1326 data = client._progress_cb[progress_id][0](progress_id, profile) |
1327 except KeyError: | 1327 except KeyError: |
1328 data = {} | 1328 data = {} |
1329 return data | 1329 return data |
1330 | 1330 |
1331 def _progressGetAll(self, profile_key): | 1331 def _progress_get_all(self, profile_key): |
1332 progress_all = self.progressGetAll(profile_key) | 1332 progress_all = self.progress_get_all(profile_key) |
1333 for profile, progress_dict in progress_all.items(): | 1333 for profile, progress_dict in progress_all.items(): |
1334 for progress_id, data in progress_dict.items(): | 1334 for progress_id, data in progress_dict.items(): |
1335 for key, value in data.items(): | 1335 for key, value in data.items(): |
1336 data[key] = str(value) | 1336 data[key] = str(value) |
1337 return progress_all | 1337 return progress_all |
1338 | 1338 |
1339 def progressGetAllMetadata(self, profile_key): | 1339 def progress_get_all_metadata(self, profile_key): |
1340 """Return all progress metadata at once | 1340 """Return all progress metadata at once |
1341 | 1341 |
1342 @param profile_key: %(doc_profile)s | 1342 @param profile_key: %(doc_profile)s |
1343 if C.PROF_KEY_ALL is used, all progress metadata from all profiles are | 1343 if C.PROF_KEY_ALL is used, all progress metadata from all profiles are |
1344 returned | 1344 returned |
1345 @return (dict[dict[dict]]): a dict which map profile to progress_dict | 1345 @return (dict[dict[dict]]): a dict which map profile to progress_dict |
1346 progress_dict map progress_id to progress_data | 1346 progress_dict map progress_id to progress_data |
1347 progress_metadata is the same dict as sent by [progressStarted] | 1347 progress_metadata is the same dict as sent by [progress_started] |
1348 """ | 1348 """ |
1349 clients = self.getClients(profile_key) | 1349 clients = self.get_clients(profile_key) |
1350 progress_all = {} | 1350 progress_all = {} |
1351 for client in clients: | 1351 for client in clients: |
1352 profile = client.profile | 1352 profile = client.profile |
1353 progress_dict = {} | 1353 progress_dict = {} |
1354 progress_all[profile] = progress_dict | 1354 progress_all[profile] = progress_dict |
1357 (__, progress_metadata), | 1357 (__, progress_metadata), |
1358 ) in client._progress_cb.items(): | 1358 ) in client._progress_cb.items(): |
1359 progress_dict[progress_id] = progress_metadata | 1359 progress_dict[progress_id] = progress_metadata |
1360 return progress_all | 1360 return progress_all |
1361 | 1361 |
1362 def progressGetAll(self, profile_key): | 1362 def progress_get_all(self, profile_key): |
1363 """Return all progress status at once | 1363 """Return all progress status at once |
1364 | 1364 |
1365 @param profile_key: %(doc_profile)s | 1365 @param profile_key: %(doc_profile)s |
1366 if C.PROF_KEY_ALL is used, all progress status from all profiles are returned | 1366 if C.PROF_KEY_ALL is used, all progress status from all profiles are returned |
1367 @return (dict[dict[dict]]): a dict which map profile to progress_dict | 1367 @return (dict[dict[dict]]): a dict which map profile to progress_dict |
1368 progress_dict map progress_id to progress_data | 1368 progress_dict map progress_id to progress_data |
1369 progress_data is the same dict as returned by [progressGet] | 1369 progress_data is the same dict as returned by [progress_get] |
1370 """ | 1370 """ |
1371 clients = self.getClients(profile_key) | 1371 clients = self.get_clients(profile_key) |
1372 progress_all = {} | 1372 progress_all = {} |
1373 for client in clients: | 1373 for client in clients: |
1374 profile = client.profile | 1374 profile = client.profile |
1375 progress_dict = {} | 1375 progress_dict = {} |
1376 progress_all[profile] = progress_dict | 1376 progress_all[profile] = progress_dict |
1377 for progress_id, (progress_cb, __) in client._progress_cb.items(): | 1377 for progress_id, (progress_cb, __) in client._progress_cb.items(): |
1378 progress_dict[progress_id] = progress_cb(progress_id, profile) | 1378 progress_dict[progress_id] = progress_cb(progress_id, profile) |
1379 return progress_all | 1379 return progress_all |
1380 | 1380 |
1381 def registerCallback(self, callback, *args, **kwargs): | 1381 def register_callback(self, callback, *args, **kwargs): |
1382 """Register a callback. | 1382 """Register a callback. |
1383 | 1383 |
1384 @param callback(callable): method to call | 1384 @param callback(callable): method to call |
1385 @param kwargs: can contain: | 1385 @param kwargs: can contain: |
1386 with_data(bool): True if the callback use the optional data dict | 1386 with_data(bool): True if the callback use the optional data dict |
1397 raise exceptions.ConflictError(_("id already registered")) | 1397 raise exceptions.ConflictError(_("id already registered")) |
1398 self._cb_map[callback_id] = (callback, args, kwargs) | 1398 self._cb_map[callback_id] = (callback, args, kwargs) |
1399 | 1399 |
1400 if "one_shot" in kwargs: # One Shot callback are removed after 30 min | 1400 if "one_shot" in kwargs: # One Shot callback are removed after 30 min |
1401 | 1401 |
1402 def purgeCallback(): | 1402 def purge_callback(): |
1403 try: | 1403 try: |
1404 self.removeCallback(callback_id) | 1404 self.removeCallback(callback_id) |
1405 except KeyError: | 1405 except KeyError: |
1406 pass | 1406 pass |
1407 | 1407 |
1408 reactor.callLater(1800, purgeCallback) | 1408 reactor.callLater(1800, purge_callback) |
1409 | 1409 |
1410 return callback_id | 1410 return callback_id |
1411 | 1411 |
1412 def removeCallback(self, callback_id): | 1412 def removeCallback(self, callback_id): |
1413 """ Remove a previously registered callback | 1413 """ Remove a previously registered callback |
1414 @param callback_id: id returned by [registerCallback] """ | 1414 @param callback_id: id returned by [register_callback] """ |
1415 log.debug("Removing callback [%s]" % callback_id) | 1415 log.debug("Removing callback [%s]" % callback_id) |
1416 del self._cb_map[callback_id] | 1416 del self._cb_map[callback_id] |
1417 | 1417 |
1418 def launchCallback(self, callback_id, data=None, profile_key=C.PROF_KEY_NONE): | 1418 def launch_callback(self, callback_id, data=None, profile_key=C.PROF_KEY_NONE): |
1419 """Launch a specific callback | 1419 """Launch a specific callback |
1420 | 1420 |
1421 @param callback_id: id of the action (callback) to launch | 1421 @param callback_id: id of the action (callback) to launch |
1422 @param data: optional data | 1422 @param data: optional data |
1423 @profile_key: %(doc_profile_key)s | 1423 @profile_key: %(doc_profile_key)s |
1428 - C.BOOL_TRUE | 1428 - C.BOOL_TRUE |
1429 - C.BOOL_FALSE | 1429 - C.BOOL_FALSE |
1430 """ | 1430 """ |
1431 # FIXME: security limit need to be checked here | 1431 # FIXME: security limit need to be checked here |
1432 try: | 1432 try: |
1433 client = self.getClient(profile_key) | 1433 client = self.get_client(profile_key) |
1434 except exceptions.NotFound: | 1434 except exceptions.NotFound: |
1435 # client is not available yet | 1435 # client is not available yet |
1436 profile = self.memory.getProfileName(profile_key) | 1436 profile = self.memory.get_profile_name(profile_key) |
1437 if not profile: | 1437 if not profile: |
1438 raise exceptions.ProfileUnknownError( | 1438 raise exceptions.ProfileUnknownError( |
1439 _("trying to launch action with a non-existant profile") | 1439 _("trying to launch action with a non-existant profile") |
1440 ) | 1440 ) |
1441 else: | 1441 else: |
1466 del kwargs["with_data"] | 1466 del kwargs["with_data"] |
1467 | 1467 |
1468 if kwargs.pop("one_shot", False): | 1468 if kwargs.pop("one_shot", False): |
1469 self.removeCallback(callback_id) | 1469 self.removeCallback(callback_id) |
1470 | 1470 |
1471 return utils.asDeferred(callback, *args, **kwargs) | 1471 return utils.as_deferred(callback, *args, **kwargs) |
1472 | 1472 |
1473 # Menus management | 1473 # Menus management |
1474 | 1474 |
1475 def _getMenuCanonicalPath(self, path): | 1475 def _get_menu_canonical_path(self, path): |
1476 """give canonical form of path | 1476 """give canonical form of path |
1477 | 1477 |
1478 canonical form is a tuple of the path were every element is stripped and lowercase | 1478 canonical form is a tuple of the path were every element is stripped and lowercase |
1479 @param path(iterable[unicode]): untranslated path to menu | 1479 @param path(iterable[unicode]): untranslated path to menu |
1480 @return (tuple[unicode]): canonical form of path | 1480 @return (tuple[unicode]): canonical form of path |
1481 """ | 1481 """ |
1482 return tuple((p.lower().strip() for p in path)) | 1482 return tuple((p.lower().strip() for p in path)) |
1483 | 1483 |
1484 def importMenu(self, path, callback, security_limit=C.NO_SECURITY_LIMIT, | 1484 def import_menu(self, path, callback, security_limit=C.NO_SECURITY_LIMIT, |
1485 help_string="", type_=C.MENU_GLOBAL): | 1485 help_string="", type_=C.MENU_GLOBAL): |
1486 r"""register a new menu for frontends | 1486 r"""register a new menu for frontends |
1487 | 1487 |
1488 @param path(iterable[unicode]): path to go to the menu | 1488 @param path(iterable[unicode]): path to go to the menu |
1489 (category/subcategory/.../item) (e.g.: ("File", "Open")) | 1489 (category/subcategory/.../item) (e.g.: ("File", "Open")) |
1490 /!\ use D_() instead of _() for translations (e.g. (D_("File"), D_("Open"))) | 1490 /!\ use D_() instead of _() for translations (e.g. (D_("File"), D_("Open"))) |
1491 untranslated/lower case path can be used to identity a menu, for this reason | 1491 untranslated/lower case path can be used to identity a menu, for this reason |
1492 it must be unique independently of case. | 1492 it must be unique independently of case. |
1493 @param callback(callable): method to be called when menuitem is selected, callable | 1493 @param callback(callable): method to be called when menuitem is selected, callable |
1494 or a callback id (string) as returned by [registerCallback] | 1494 or a callback id (string) as returned by [register_callback] |
1495 @param security_limit(int): %(doc_security_limit)s | 1495 @param security_limit(int): %(doc_security_limit)s |
1496 /!\ security_limit MUST be added to data in launchCallback if used #TODO | 1496 /!\ security_limit MUST be added to data in launch_callback if used #TODO |
1497 @param help_string(unicode): string used to indicate what the menu do (can be | 1497 @param help_string(unicode): string used to indicate what the menu do (can be |
1498 show as a tooltip). | 1498 show as a tooltip). |
1499 /!\ use D_() instead of _() for translations | 1499 /!\ use D_() instead of _() for translations |
1500 @param type(unicode): one of: | 1500 @param type(unicode): one of: |
1501 - C.MENU_GLOBAL: classical menu, can be shown in a menubar on top (e.g. | 1501 - C.MENU_GLOBAL: classical menu, can be shown in a menubar on top (e.g. |
1515 menu_data must contain a "group" data | 1515 menu_data must contain a "group" data |
1516 @return (unicode): menu_id (same as callback_id) | 1516 @return (unicode): menu_id (same as callback_id) |
1517 """ | 1517 """ |
1518 | 1518 |
1519 if callable(callback): | 1519 if callable(callback): |
1520 callback_id = self.registerCallback(callback, with_data=True) | 1520 callback_id = self.register_callback(callback, with_data=True) |
1521 elif isinstance(callback, str): | 1521 elif isinstance(callback, str): |
1522 # The callback is already registered | 1522 # The callback is already registered |
1523 callback_id = callback | 1523 callback_id = callback |
1524 try: | 1524 try: |
1525 callback, args, kwargs = self._cb_map[callback_id] | 1525 callback, args, kwargs = self._cb_map[callback_id] |
1533 if menu_data["path"] == path and menu_data["type"] == type_: | 1533 if menu_data["path"] == path and menu_data["type"] == type_: |
1534 raise exceptions.ConflictError( | 1534 raise exceptions.ConflictError( |
1535 _("A menu with the same path and type already exists") | 1535 _("A menu with the same path and type already exists") |
1536 ) | 1536 ) |
1537 | 1537 |
1538 path_canonical = self._getMenuCanonicalPath(path) | 1538 path_canonical = self._get_menu_canonical_path(path) |
1539 menu_key = (type_, path_canonical) | 1539 menu_key = (type_, path_canonical) |
1540 | 1540 |
1541 if menu_key in self._menus_paths: | 1541 if menu_key in self._menus_paths: |
1542 raise exceptions.ConflictError( | 1542 raise exceptions.ConflictError( |
1543 "this menu path is already used: {path} ({menu_key})".format( | 1543 "this menu path is already used: {path} ({menu_key})".format( |
1556 self._menus[callback_id] = menu_data | 1556 self._menus[callback_id] = menu_data |
1557 self._menus_paths[menu_key] = callback_id | 1557 self._menus_paths[menu_key] = callback_id |
1558 | 1558 |
1559 return callback_id | 1559 return callback_id |
1560 | 1560 |
1561 def getMenus(self, language="", security_limit=C.NO_SECURITY_LIMIT): | 1561 def get_menus(self, language="", security_limit=C.NO_SECURITY_LIMIT): |
1562 """Return all menus registered | 1562 """Return all menus registered |
1563 | 1563 |
1564 @param language: language used for translation, or empty string for default | 1564 @param language: language used for translation, or empty string for default |
1565 @param security_limit: %(doc_security_limit)s | 1565 @param security_limit: %(doc_security_limit)s |
1566 @return: array of tuple with: | 1566 @return: array of tuple with: |
1580 if security_limit != C.NO_SECURITY_LIMIT and ( | 1580 if security_limit != C.NO_SECURITY_LIMIT and ( |
1581 menu_security_limit == C.NO_SECURITY_LIMIT | 1581 menu_security_limit == C.NO_SECURITY_LIMIT |
1582 or menu_security_limit > security_limit | 1582 or menu_security_limit > security_limit |
1583 ): | 1583 ): |
1584 continue | 1584 continue |
1585 languageSwitch(language) | 1585 language_switch(language) |
1586 path_i18n = [_(elt) for elt in path] | 1586 path_i18n = [_(elt) for elt in path] |
1587 languageSwitch() | 1587 language_switch() |
1588 extra = {} # TODO: manage extra data like icon | 1588 extra = {} # TODO: manage extra data like icon |
1589 ret.append((menu_id, type_, path, path_i18n, extra)) | 1589 ret.append((menu_id, type_, path, path_i18n, extra)) |
1590 | 1590 |
1591 return ret | 1591 return ret |
1592 | 1592 |
1593 def _launchMenu(self, menu_type, path, data=None, security_limit=C.NO_SECURITY_LIMIT, | 1593 def _launch_menu(self, menu_type, path, data=None, security_limit=C.NO_SECURITY_LIMIT, |
1594 profile_key=C.PROF_KEY_NONE): | 1594 profile_key=C.PROF_KEY_NONE): |
1595 client = self.getClient(profile_key) | 1595 client = self.get_client(profile_key) |
1596 return self.launchMenu(client, menu_type, path, data, security_limit) | 1596 return self.launch_menu(client, menu_type, path, data, security_limit) |
1597 | 1597 |
1598 def launchMenu(self, client, menu_type, path, data=None, | 1598 def launch_menu(self, client, menu_type, path, data=None, |
1599 security_limit=C.NO_SECURITY_LIMIT): | 1599 security_limit=C.NO_SECURITY_LIMIT): |
1600 """launch action a menu action | 1600 """launch action a menu action |
1601 | 1601 |
1602 @param menu_type(unicode): type of menu to launch | 1602 @param menu_type(unicode): type of menu to launch |
1603 @param path(iterable[unicode]): canonical path of the menu | 1603 @param path(iterable[unicode]): canonical path of the menu |
1604 @params data(dict): menu data | 1604 @params data(dict): menu data |
1605 @raise NotFound: this path is not known | 1605 @raise NotFound: this path is not known |
1606 """ | 1606 """ |
1607 # FIXME: manage security_limit here | 1607 # FIXME: manage security_limit here |
1608 # defaut security limit should be high instead of C.NO_SECURITY_LIMIT | 1608 # defaut security limit should be high instead of C.NO_SECURITY_LIMIT |
1609 canonical_path = self._getMenuCanonicalPath(path) | 1609 canonical_path = self._get_menu_canonical_path(path) |
1610 menu_key = (menu_type, canonical_path) | 1610 menu_key = (menu_type, canonical_path) |
1611 try: | 1611 try: |
1612 callback_id = self._menus_paths[menu_key] | 1612 callback_id = self._menus_paths[menu_key] |
1613 except KeyError: | 1613 except KeyError: |
1614 raise exceptions.NotFound( | 1614 raise exceptions.NotFound( |
1615 "Can't find menu {path} ({menu_type})".format( | 1615 "Can't find menu {path} ({menu_type})".format( |
1616 path=canonical_path, menu_type=menu_type | 1616 path=canonical_path, menu_type=menu_type |
1617 ) | 1617 ) |
1618 ) | 1618 ) |
1619 return self.launchCallback(callback_id, data, client.profile) | 1619 return self.launch_callback(callback_id, data, client.profile) |
1620 | 1620 |
1621 def getMenuHelp(self, menu_id, language=""): | 1621 def get_menu_help(self, menu_id, language=""): |
1622 """return the help string of the menu | 1622 """return the help string of the menu |
1623 | 1623 |
1624 @param menu_id: id of the menu (same as callback_id) | 1624 @param menu_id: id of the menu (same as callback_id) |
1625 @param language: language used for translation, or empty string for default | 1625 @param language: language used for translation, or empty string for default |
1626 @param return: translated help | 1626 @param return: translated help |
1628 """ | 1628 """ |
1629 try: | 1629 try: |
1630 menu_data = self._menus[menu_id] | 1630 menu_data = self._menus[menu_id] |
1631 except KeyError: | 1631 except KeyError: |
1632 raise exceptions.DataError("Trying to access an unknown menu") | 1632 raise exceptions.DataError("Trying to access an unknown menu") |
1633 languageSwitch(language) | 1633 language_switch(language) |
1634 help_string = _(menu_data["help_string"]) | 1634 help_string = _(menu_data["help_string"]) |
1635 languageSwitch() | 1635 language_switch() |
1636 return help_string | 1636 return help_string |