From a06fa2de677afad437622216fac7971b727ac569 Mon Sep 17 00:00:00 2001 From: Lance Stout Date: Thu, 26 Jul 2012 23:04:16 -0700 Subject: [PATCH] Enhance plugin config with attribute accessors. This makes updating the config after plugin initialization much easier. --- .../features/feature_mechanisms/mechanisms.py | 16 +++--- sleekxmpp/plugins/base.py | 36 +++++++++++- sleekxmpp/plugins/xep_0027/gpg.py | 13 +++-- sleekxmpp/plugins/xep_0030/disco.py | 7 ++- sleekxmpp/plugins/xep_0047/ibb.py | 13 +++-- sleekxmpp/plugins/xep_0050/adhoc.py | 10 +++- sleekxmpp/plugins/xep_0077/register.py | 10 ++-- sleekxmpp/plugins/xep_0078/legacyauth.py | 7 ++- sleekxmpp/plugins/xep_0086/legacy_error.py | 5 +- sleekxmpp/plugins/xep_0092/version.py | 17 ++++-- sleekxmpp/plugins/xep_0115/caps.py | 9 +-- sleekxmpp/plugins/xep_0184/receipt.py | 7 ++- .../plugins/xep_0198/stream_management.py | 55 ++++++++++--------- sleekxmpp/plugins/xep_0199/ping.py | 9 +-- sleekxmpp/plugins/xep_0202/time.py | 21 +++---- sleekxmpp/plugins/xep_0256.py | 5 +- 16 files changed, 154 insertions(+), 86 deletions(-) diff --git a/sleekxmpp/features/feature_mechanisms/mechanisms.py b/sleekxmpp/features/feature_mechanisms/mechanisms.py index 930aa8fe..2ab7b0a4 100644 --- a/sleekxmpp/features/feature_mechanisms/mechanisms.py +++ b/sleekxmpp/features/feature_mechanisms/mechanisms.py @@ -29,10 +29,13 @@ class FeatureMechanisms(BasePlugin): description = 'RFC 6120: Stream Feature: SASL' dependencies = set() stanza = stanza + default_config = { + 'use_mech': None, + 'sasl_callback': None, + 'order': 100 + } def plugin_init(self): - self.use_mech = self.config.get('use_mech', None) - if not self.use_mech and not self.xmpp.boundjid.user: self.use_mech = 'ANONYMOUS' @@ -53,15 +56,14 @@ class FeatureMechanisms(BasePlugin): values[value] = creds[value] mech.fulfill(values) - sasl_callback = self.config.get('sasl_callback', None) - if sasl_callback is None: - sasl_callback = basic_callback + if self.sasl_callback is None: + self.sasl_callback = basic_callback self.mech = None self.sasl = suelta.SASL(self.xmpp.boundjid.domain, 'xmpp', username=self.xmpp.boundjid.user, sec_query=suelta.sec_query_allow, - request_values=sasl_callback, + request_values=self.sasl_callback, tls_active=tls_active, mech=self.use_mech) @@ -95,7 +97,7 @@ class FeatureMechanisms(BasePlugin): self.xmpp.register_feature('mechanisms', self._handle_sasl_auth, restart=True, - order=self.config.get('order', 100)) + order=self.order) def _handle_sasl_auth(self, features): """ diff --git a/sleekxmpp/plugins/base.py b/sleekxmpp/plugins/base.py index 26f0c827..67675908 100644 --- a/sleekxmpp/plugins/base.py +++ b/sleekxmpp/plugins/base.py @@ -14,6 +14,7 @@ """ import sys +import copy import logging import threading @@ -272,6 +273,14 @@ class BasePlugin(object): #: be initialized as needed if this plugin is enabled. dependencies = set() + #: The basic, standard configuration for the plugin, which may + #: be overridden when initializing the plugin. The configuration + #: fields included here may be accessed directly as attributes of + #: the plugin. For example, including the configuration field 'foo' + #: would mean accessing `plugin.foo` returns the current value of + #: `plugin.config['foo']`. + default_config = {} + def __init__(self, xmpp, config=None): self.xmpp = xmpp if self.xmpp: @@ -279,7 +288,32 @@ class BasePlugin(object): #: A plugin's behaviour may be configurable, in which case those #: configuration settings will be provided as a dictionary. - self.config = config if config is not None else {} + self.config = copy.copy(self.default_config) + if config: + self.config.update(config) + + def __getattr__(self, key): + """Provide direct access to configuration fields. + + If the standard configuration includes the option `'foo'`, then + accessing `self.foo` should be the same as `self.config['foo']`. + """ + if key in self.default_config: + return self.config.get(key, None) + else: + return object.__getattribute__(self, key) + + def __setattr__(self, key, value): + """Provide direct assignment to configuration fields. + + If the standard configuration includes the option `'foo'`, then + assigning to `self.foo` should be the same as assigning to + `self.config['foo']`. + """ + if key in self.default_config: + self.config[key] = value + else: + super(BasePlugin, self).__setattr__(key, value) def _init(self): """Initialize plugin state, such as registering event handlers. diff --git a/sleekxmpp/plugins/xep_0027/gpg.py b/sleekxmpp/plugins/xep_0027/gpg.py index 3ca9c36d..2aa6e5a0 100644 --- a/sleekxmpp/plugins/xep_0027/gpg.py +++ b/sleekxmpp/plugins/xep_0027/gpg.py @@ -40,14 +40,15 @@ class XEP_0027(BasePlugin): description = 'XEP-0027: Current Jabber OpenPGP Usage' dependencies = set() stanza = stanza + default_config = { + 'gpg_binary': 'gpg', + 'gpg_home': '', + 'use_agent': True, + 'keyring': None, + 'key_server': 'pgp.mit.edu' + } def plugin_init(self): - self.gpg_binary = self.config.get('gpg_binary', 'gpg') - self.gpg_home = self.config.get('gpg_home', '') - self.use_agent = self.config.get('use_agent', True) - self.keyring = self.config.get('keyring', None) - self.key_server = self.config.get('key_server', 'pgp.mit.edu') - self.gpg = GPG(gnupghome=self.gpg_home, gpgbinary=self.gpg_binary, use_agent=self.use_agent, diff --git a/sleekxmpp/plugins/xep_0030/disco.py b/sleekxmpp/plugins/xep_0030/disco.py index eeb977b1..be66b6fd 100644 --- a/sleekxmpp/plugins/xep_0030/disco.py +++ b/sleekxmpp/plugins/xep_0030/disco.py @@ -88,6 +88,10 @@ class XEP_0030(BasePlugin): description = 'XEP-0030: Service Discovery' dependencies = set() stanza = stanza + default_config = { + 'use_cache': True, + 'wrap_results': False + } def plugin_init(self): """ @@ -108,9 +112,6 @@ class XEP_0030(BasePlugin): self.static = StaticDisco(self.xmpp, self) - self.use_cache = self.config.get('use_cache', True) - self.wrap_results = self.config.get('wrap_results', False) - self._disco_ops = [ 'get_info', 'set_info', 'set_identities', 'set_features', 'get_items', 'set_items', 'del_items', 'add_identity', diff --git a/sleekxmpp/plugins/xep_0047/ibb.py b/sleekxmpp/plugins/xep_0047/ibb.py index 2b8c57d4..fb48a9b9 100644 --- a/sleekxmpp/plugins/xep_0047/ibb.py +++ b/sleekxmpp/plugins/xep_0047/ibb.py @@ -20,18 +20,19 @@ class XEP_0047(BasePlugin): description = 'XEP-0047: In-band Bytestreams' dependencies = set(['xep_0030']) stanza = stanza + default_config = { + 'max_block_size': 8192, + 'window_size': 1, + 'auto_accept': True, + 'accept_stream': None + } def plugin_init(self): self.streams = {} - self.pending_streams = {3: 5} + self.pending_streams = {} self.pending_close_streams = {} self._stream_lock = threading.Lock() - self.max_block_size = self.config.get('max_block_size', 8192) - self.window_size = self.config.get('window_size', 1) - self.auto_accept = self.config.get('auto_accept', True) - self.accept_stream = self.config.get('accept_stream', None) - register_stanza_plugin(Iq, Open) register_stanza_plugin(Iq, Close) register_stanza_plugin(Iq, Data) diff --git a/sleekxmpp/plugins/xep_0050/adhoc.py b/sleekxmpp/plugins/xep_0050/adhoc.py index a833221a..032b987a 100644 --- a/sleekxmpp/plugins/xep_0050/adhoc.py +++ b/sleekxmpp/plugins/xep_0050/adhoc.py @@ -82,12 +82,18 @@ class XEP_0050(BasePlugin): description = 'XEP-0050: Ad-Hoc Commands' dependencies = set(['xep_0030', 'xep_0004']) stanza = stanza + default_config = { + 'threaded': True, + 'session_db': None + } def plugin_init(self): """Start the XEP-0050 plugin.""" - self.threaded = self.config.get('threaded', True) + self.sessions = self.session_db + if self.sessions is None: + self.sessions = {} + self.commands = {} - self.sessions = self.config.get('session_db', {}) self.xmpp.register_handler( Callback("Ad-Hoc Execute", diff --git a/sleekxmpp/plugins/xep_0077/register.py b/sleekxmpp/plugins/xep_0077/register.py index 7f00354b..d4da21a5 100644 --- a/sleekxmpp/plugins/xep_0077/register.py +++ b/sleekxmpp/plugins/xep_0077/register.py @@ -27,10 +27,12 @@ class XEP_0077(BasePlugin): description = 'XEP-0077: In-Band Registration' dependencies = set(['xep_0004', 'xep_0066']) stanza = stanza + default_config = { + 'create_account': True, + 'order': 50 + } def plugin_init(self): - self.create_account = self.config.get('create_account', True) - register_stanza_plugin(StreamFeatures, RegisterFeature) register_stanza_plugin(Iq, Register) @@ -38,14 +40,14 @@ class XEP_0077(BasePlugin): self.xmpp.register_feature('register', self._handle_register_feature, restart=False, - order=self.config.get('order', 50)) + order=self.order) register_stanza_plugin(Register, self.xmpp['xep_0004'].stanza.Form) register_stanza_plugin(Register, self.xmpp['xep_0066'].stanza.OOB) def plugin_end(self): if not self.xmpp.is_component: - self.xmpp.unregister_feature('register', self.config.get('order', 50)) + self.xmpp.unregister_feature('register', self.order) def _handle_register_feature(self, features): if 'mechanisms' in self.xmpp.features: diff --git a/sleekxmpp/plugins/xep_0078/legacyauth.py b/sleekxmpp/plugins/xep_0078/legacyauth.py index 8ea78fba..5c4045d8 100644 --- a/sleekxmpp/plugins/xep_0078/legacyauth.py +++ b/sleekxmpp/plugins/xep_0078/legacyauth.py @@ -34,18 +34,21 @@ class XEP_0078(BasePlugin): description = 'XEP-0078: Non-SASL Authentication' dependencies = set() stanza = stanza + default_config = { + 'order': 15 + } def plugin_init(self): self.xmpp.register_feature('auth', self._handle_auth, restart=False, - order=self.config.get('order', 15)) + order=self.order) register_stanza_plugin(Iq, stanza.IqAuth) register_stanza_plugin(StreamFeatures, stanza.AuthFeature) def plugin_end(self): - self.xmpp.unregister_feature('auth', self.config.get('order', 15)) + self.xmpp.unregister_feature('auth', self.order) def _handle_auth(self, features): # If we can or have already authenticated with SASL, do nothing. diff --git a/sleekxmpp/plugins/xep_0086/legacy_error.py b/sleekxmpp/plugins/xep_0086/legacy_error.py index bed22ee2..f7d0ac9c 100644 --- a/sleekxmpp/plugins/xep_0086/legacy_error.py +++ b/sleekxmpp/plugins/xep_0086/legacy_error.py @@ -37,7 +37,10 @@ class XEP_0086(BasePlugin): description = 'XEP-0086: Error Condition Mappings' dependencies = set() stanza = stanza + default_config = { + 'override': True + } def plugin_init(self): register_stanza_plugin(Error, LegacyError, - overrides=self.config.get('override', True)) + overrides=self.override) diff --git a/sleekxmpp/plugins/xep_0092/version.py b/sleekxmpp/plugins/xep_0092/version.py index 463da158..35813e1d 100644 --- a/sleekxmpp/plugins/xep_0092/version.py +++ b/sleekxmpp/plugins/xep_0092/version.py @@ -30,16 +30,18 @@ class XEP_0092(BasePlugin): description = 'XEP-0092: Software Version' dependencies = set(['xep_0030']) stanza = stanza + default_config = { + 'software_name': 'SleekXMPP', + 'version': sleekxmpp.__version__, + 'os': '' + } def plugin_init(self): """ Start the XEP-0092 plugin. """ - self.name = self.config.get('name', 'SleekXMPP') - self.version = self.config.get('version', sleekxmpp.__version__) - self.os = self.config.get('os', '') - - self.getVersion = self.get_version + if 'name' in self.config: + self.software_name = self.config['name'] self.xmpp.register_handler( Callback('Software Version', @@ -63,7 +65,7 @@ class XEP_0092(BasePlugin): iq -- The Iq stanza containing the software version query. """ iq.reply() - iq['software_version']['name'] = self.name + iq['software_version']['name'] = self.software_name iq['software_version']['version'] = self.version iq['software_version']['os'] = self.os iq.send() @@ -88,3 +90,6 @@ class XEP_0092(BasePlugin): del values['lang'] return values return False + + +XEP_0092.getVersion = XEP_0092.get_version diff --git a/sleekxmpp/plugins/xep_0115/caps.py b/sleekxmpp/plugins/xep_0115/caps.py index 8ce10edb..15ddb283 100644 --- a/sleekxmpp/plugins/xep_0115/caps.py +++ b/sleekxmpp/plugins/xep_0115/caps.py @@ -33,16 +33,17 @@ class XEP_0115(BasePlugin): description = 'XEP-0115: Entity Capabilities' dependencies = set(['xep_0030', 'xep_0128', 'xep_0004']) stanza = stanza + default_config = { + 'hash': 'sha-1', + 'caps_node': None, + 'broadcast': True + } def plugin_init(self): self.hashes = {'sha-1': hashlib.sha1, 'sha1': hashlib.sha1, 'md5': hashlib.md5} - self.hash = self.config.get('hash', 'sha-1') - self.caps_node = self.config.get('caps_node', None) - self.broadcast = self.config.get('broadcast', True) - if self.caps_node is None: ver = sleekxmpp.__version__ self.caps_node = 'http://sleekxmpp.com/ver/%s' % ver diff --git a/sleekxmpp/plugins/xep_0184/receipt.py b/sleekxmpp/plugins/xep_0184/receipt.py index 2b939321..1fda2066 100644 --- a/sleekxmpp/plugins/xep_0184/receipt.py +++ b/sleekxmpp/plugins/xep_0184/receipt.py @@ -26,13 +26,14 @@ class XEP_0184(BasePlugin): description = 'XEP-0184: Message Delivery Receipts' dependencies = set(['xep_0030']) stanza = stanza + default_config = { + 'auto_ack': True, + 'auto_request': False + } ack_types = ('normal', 'chat', 'headline') def plugin_init(self): - self.auto_ack = self.config.get('auto_ack', True) - self.auto_request = self.config.get('auto_request', False) - register_stanza_plugin(Message, Request) register_stanza_plugin(Message, Received) diff --git a/sleekxmpp/plugins/xep_0198/stream_management.py b/sleekxmpp/plugins/xep_0198/stream_management.py index a150ad39..48029913 100644 --- a/sleekxmpp/plugins/xep_0198/stream_management.py +++ b/sleekxmpp/plugins/xep_0198/stream_management.py @@ -34,6 +34,32 @@ class XEP_0198(BasePlugin): description = 'XEP-0198: Stream Management' dependencies = set() stanza = stanza + default_config = { + #: The last ack number received from the server. + 'last_ack': 0, + + #: The number of stanzas to wait between sending ack requests to + #: the server. Setting this to ``1`` will send an ack request after + #: every sent stanza. Defaults to ``5``. + 'window': 5, + + #: The stream management ID for the stream. Knowing this value is + #: required in order to do stream resumption. + 'sm_id': None, + + #: A counter of handled incoming stanzas, mod 2^32. + 'handled': 0, + + #: A counter of unacked outgoing stanzas, mod 2^32. + 'seq': 0, + + #: Control whether or not the ability to resume the stream will be + #: requested when enabling stream management. Defaults to ``True``. + 'allow_resume': True, + + 'order': 10100, + 'resume_order': 9000 + } def plugin_init(self): """Start the XEP-0198 plugin.""" @@ -43,30 +69,9 @@ class XEP_0198(BasePlugin): if self.xmpp.is_component: return - #: The stream management ID for the stream. Knowing this value is - #: required in order to do stream resumption. - self.sm_id = self.config.get('sm_id', None) - - #: A counter of handled incoming stanzas, mod 2^32. - self.handled = self.config.get('handled', 0) - - #: A counter of unacked outgoing stanzas, mod 2^32. - self.seq = self.config.get('seq', 0) - - #: The last ack number received from the server. - self.last_ack = self.config.get('last_ack', 0) - - #: The number of stanzas to wait between sending ack requests to - #: the server. Setting this to ``1`` will send an ack request after - #: every sent stanza. Defaults to ``5``. - self.window = self.config.get('window', 5) self.window_counter = self.window self.window_counter_lock = threading.Lock() - #: Control whether or not the ability to resume the stream will be - #: requested when enabling stream management. Defaults to ``True``. - self.allow_resume = self.config.get('allow_resume', True) - self.enabled = threading.Event() self.unacked_queue = collections.deque() @@ -92,11 +97,11 @@ class XEP_0198(BasePlugin): self.xmpp.register_feature('sm', self._handle_sm_feature, restart=True, - order=self.config.get('order', 10100)) + order=self.order) self.xmpp.register_feature('sm', self._handle_sm_feature, restart=True, - order=self.config.get('resume_order', 9000)) + order=self.resume_order) self.xmpp.register_handler( Callback('Stream Management Enabled', @@ -137,8 +142,8 @@ class XEP_0198(BasePlugin): if self.xmpp.is_component: return - self.xmpp.unregister_feature('sm', self.config.get('order', 10100)) - self.xmpp.unregister_feature('sm', self.config.get('resume_order', 9000)) + self.xmpp.unregister_feature('sm', self.order) + self.xmpp.unregister_feature('sm', self.resume_order) self.xmpp.del_event_handler('session_end', self.session_end) self.xmpp.del_filter('in', self._handle_incoming) self.xmpp.del_filter('out_sync', self._handle_outgoing) diff --git a/sleekxmpp/plugins/xep_0199/ping.py b/sleekxmpp/plugins/xep_0199/ping.py index b9d145aa..0bdeabf3 100644 --- a/sleekxmpp/plugins/xep_0199/ping.py +++ b/sleekxmpp/plugins/xep_0199/ping.py @@ -51,15 +51,16 @@ class XEP_0199(BasePlugin): description = 'XEP-0199: XMPP Ping' dependencies = set(['xep_0030']) stanza = stanza + default_config = { + 'keepalive': False, + 'frequency': 300, + 'timeout': 30 + } def plugin_init(self): """ Start the XEP-0199 plugin. """ - self.keepalive = self.config.get('keepalive', False) - self.frequency = float(self.config.get('frequency', 300)) - self.timeout = self.config.get('timeout', 30) - register_stanza_plugin(Iq, Ping) self.xmpp.register_handler( diff --git a/sleekxmpp/plugins/xep_0202/time.py b/sleekxmpp/plugins/xep_0202/time.py index 50af4730..fe20449d 100644 --- a/sleekxmpp/plugins/xep_0202/time.py +++ b/sleekxmpp/plugins/xep_0202/time.py @@ -30,21 +30,22 @@ class XEP_0202(BasePlugin): description = 'XEP-0202: Entity Time' dependencies = set(['xep_0030', 'xep_0082']) stanza = stanza + default_config = { + #: As a default, respond to time requests with the + #: local time returned by XEP-0082. However, a + #: custom function can be supplied which accepts + #: the JID of the entity to query for the time. + 'local_time': None, + 'tz_offset': 0 + } def plugin_init(self): """Start the XEP-0203 plugin.""" - self.tz_offset = self.config.get('tz_offset', 0) - - # As a default, respond to time requests with the - # local time returned by XEP-0082. However, a - # custom function can be supplied which accepts - # the JID of the entity to query for the time. - self.local_time = self.config.get('local_time', None) - - def default_local_time(jid): - return xep_0082.datetime(offset=self.tz_offset) if not self.local_time: + def default_local_time(jid): + return xep_0082.datetime(offset=self.tz_offset) + self.local_time = default_local_time self.xmpp.registerHandler( diff --git a/sleekxmpp/plugins/xep_0256.py b/sleekxmpp/plugins/xep_0256.py index dd407fff..0db8ea3b 100644 --- a/sleekxmpp/plugins/xep_0256.py +++ b/sleekxmpp/plugins/xep_0256.py @@ -25,10 +25,11 @@ class XEP_0256(BasePlugin): description = 'XEP-0256: Last Activity in Presence' dependencies = set(['xep_0012']) stanza = stanza + default_config = { + 'auto_last_activity': False + } def plugin_init(self): - self.auto_last_activity = self.config.get('auto_last_activity', False) - register_stanza_plugin(Presence, LastActivity) self.xmpp.add_filter('out', self._initial_presence_activity)