Updated XEP-0202 plugin to new format and use XEP-0082.

This commit is contained in:
Lance Stout 2011-07-03 15:30:06 -07:00
parent c98f5d4450
commit ec3a14e6d9
4 changed files with 227 additions and 117 deletions

View file

@ -1,117 +0,0 @@
"""
SleekXMPP: The Sleek XMPP Library
Copyright (C) 2010 Nathanael C. Fritz
This file is part of SleekXMPP.
See the file LICENSE for copying permission.
"""
from datetime import datetime, tzinfo
import logging
import time
from . import base
from .. stanza.iq import Iq
from .. xmlstream.handler.callback import Callback
from .. xmlstream.matcher.xpath import MatchXPath
from .. xmlstream import ElementBase, ET, JID, register_stanza_plugin
log = logging.getLogger(__name__)
class EntityTime(ElementBase):
name = 'time'
namespace = 'urn:xmpp:time'
plugin_attrib = 'entity_time'
interfaces = set(('tzo', 'utc'))
sub_interfaces = set(('tzo', 'utc'))
#def get_tzo(self):
# TODO: Right now it returns a string but maybe it should
# return a datetime.tzinfo object or maybe a datetime.timedelta?
#pass
def set_tzo(self, tzo):
if isinstance(tzo, tzinfo):
td = datetime.now(tzo).utcoffset() # What if we are faking the time? datetime.now() shouldn't be used here'
seconds = td.seconds + td.days * 24 * 3600
sign = ('+' if seconds >= 0 else '-')
minutes = abs(seconds // 60)
tzo = '{sign}{hours:02d}:{minutes:02d}'.format(sign=sign, hours=minutes//60, minutes=minutes%60)
elif not isinstance(tzo, str):
raise TypeError('The time should be a string or a datetime.tzinfo object.')
self._set_sub_text('tzo', tzo)
def get_utc(self):
# Returns a datetime object instead the string. Is this a good idea?
value = self._get_sub_text('utc')
if '.' in value:
return datetime.strptime(value, '%Y-%m-%dT%H:%M:%S.%fZ')
else:
return datetime.strptime(value, '%Y-%m-%dT%H:%M:%SZ')
def set_utc(self, tim=None):
if isinstance(tim, datetime):
if tim.utcoffset():
tim = tim - tim.utcoffset()
tim = tim.strftime('%Y-%m-%dT%H:%M:%SZ')
elif isinstance(tim, time.struct_time):
tim = time.strftime('%Y-%m-%dT%H:%M:%SZ', tim)
elif not isinstance(tim, str):
raise TypeError('The time should be a string or a datetime.datetime or time.struct_time object.')
self._set_sub_text('utc', tim)
class xep_0202(base.base_plugin):
"""
XEP-0202 Entity Time
"""
def plugin_init(self):
self.description = "Entity Time"
self.xep = "0202"
self.xmpp.registerHandler(
Callback('Time Request',
MatchXPath('{%s}iq/{%s}time' % (self.xmpp.default_ns,
EntityTime.namespace)),
self.handle_entity_time_query))
register_stanza_plugin(Iq, EntityTime)
self.xmpp.add_event_handler('entity_time_request', self.handle_entity_time)
def post_init(self):
base.base_plugin.post_init(self)
self.xmpp.plugin['xep_0030'].add_feature('urn:xmpp:time')
def handle_entity_time_query(self, iq):
if iq['type'] == 'get':
log.debug("Entity time requested by %s" % iq['from'])
self.xmpp.event('entity_time_request', iq)
elif iq['type'] == 'result':
log.debug("Entity time result from %s" % iq['from'])
self.xmpp.event('entity_time', iq)
def handle_entity_time(self, iq):
iq = iq.reply()
iq.enable('entity_time')
tzo = time.strftime('%z') # %z is not on all ANSI C libraries
tzo = tzo[:3] + ':' + tzo[3:]
iq['entity_time']['tzo'] = tzo
iq['entity_time']['utc'] = datetime.utcnow()
iq.send()
def get_entity_time(self, jid):
iq = self.xmpp.makeIqGet()
iq.enable('entity_time')
iq.attrib['to'] = jid
iq.attrib['from'] = self.xmpp.boundjid.full
id = iq.get('id')
result = iq.send()
if result and result is not None and result.get('type', 'error') != 'error':
return {'utc': result['entity_time']['utc'], 'tzo': result['entity_time']['tzo']}
else:
return False

View file

@ -0,0 +1,11 @@
"""
SleekXMPP: The Sleek XMPP Library
Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout
This file is part of SleekXMPP.
See the file LICENSE for copying permission.
"""
from sleekxmpp.plugins.xep_0202 import stanza
from sleekxmpp.plugins.xep_0202.stanza import EntityTime
from sleekxmpp.plugins.xep_0202.time import xep_0202

View file

@ -0,0 +1,126 @@
"""
SleekXMPP: The Sleek XMPP Library
Copyright (C) 2010 Nathanael C. Fritz
This file is part of SleekXMPP.
See the file LICENSE for copying permission.
"""
import datetime as dt
from dateutil.tz import tzoffset, tzutc
from sleekxmpp.xmlstream import ElementBase
from sleekxmpp.plugins import xep_0082
class EntityTime(ElementBase):
"""
The <time> element represents the local time for an XMPP agent.
The time is expressed in UTC to make synchronization easier
between entities, but the offset for the local timezone is also
included.
Example <time> stanzas:
<iq type="result">
<time xmlns="urn:xmpp:time">
<utc>2011-07-03T11:37:12.234569</utc>
<tzo>-07:00</tzo>
</time>
</iq>
Stanza Interface:
time -- The local time for the entity (updates utc and tzo).
utc -- The UTC equivalent to local time.
tzo -- The local timezone offset from UTC.
Methods:
get_time -- Return local time datetime object.
set_time -- Set UTC and TZO fields.
del_time -- Remove both UTC and TZO fields.
get_utc -- Return datetime object of UTC time.
set_utc -- Set the UTC time.
get_tzo -- Return tzinfo object.
set_tzo -- Set the local timezone offset.
"""
name = 'time'
namespace = 'urn:xmpp:time'
plugin_attrib = 'entity_time'
interfaces = set(('tzo', 'utc', 'time'))
sub_interfaces = interfaces
def set_time(self, value):
"""
Set both the UTC and TZO fields given a time object.
Arguments:
value -- A datetime object or properly formatted
string equivalent.
"""
date = value
if not isinstance(value, dt.datetime):
date = xep_0082.parse(value)
self['utc'] = date
self['tzo'] = date.tzinfo
def get_time(self):
"""
Return the entity's local time based on the UTC and TZO data.
"""
date = self['utc']
tz = self['tzo']
return date.astimezone(tz)
def del_time(self):
"""Remove both the UTC and TZO fields."""
del self['utc']
del self['tzo']
def get_tzo(self):
"""
Return the timezone offset from UTC as a tzinfo object.
"""
tzo = self._get_sub_text('tzo')
if tzo == '':
tzo = 'Z'
time = xep_0082.parse('00:00:00%s' % tzo)
return time.tzinfo
def set_tzo(self, value):
"""
Set the timezone offset from UTC.
Arguments:
value -- Either a tzinfo object or the number of
seconds (positive or negative) to offset.
"""
time = xep_0082.time(offset=value)
if xep_0082.parse(time).tzinfo == tzutc():
self._set_sub_text('tzo', 'Z')
else:
self._set_sub_text('tzo', time[-6:])
def get_utc(self):
"""
Return the time in UTC as a datetime object.
"""
value = self._get_sub_text('utc')
if value == '':
return xep_0082.parse(xep_0082.datetime())
return xep_0082.parse('%sZ' % value)
def set_utc(self, value):
"""
Set the time in UTC.
Arguments:
value -- A datetime object or properly formatted
string equivalent.
"""
date = value
if not isinstance(value, dt.datetime):
date = xep_0082.parse(value)
date = date.astimezone(tzutc())
value = xep_0082.format_datetime(date)[:-1]
self._set_sub_text('utc', value)

View file

@ -0,0 +1,90 @@
"""
SleekXMPP: The Sleek XMPP Library
Copyright (C) 2010 Nathanael C. Fritz
This file is part of SleekXMPP.
See the file LICENSE for copying permission.
"""
import logging
from sleekxmpp.stanza.iq import Iq
from sleekxmpp.xmlstream import register_stanza_plugin
from sleekxmpp.xmlstream.handler import Callback
from sleekxmpp.xmlstream.matcher import StanzaPath
from sleekxmpp.plugins.base import base_plugin
from sleekxmpp.plugins import xep_0082
from sleekxmpp.plugins.xep_0202 import stanza
log = logging.getLogger(__name__)
class xep_0202(base_plugin):
"""
XEP-0202: Entity Time
"""
def plugin_init(self):
"""Start the XEP-0203 plugin."""
self.xep = '0202'
self.description = 'Entity Time'
self.stanza = stanza
# 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)
if not self.local_time:
self.local_time = lambda x: xep_0082.datetime()
self.xmpp.registerHandler(
Callback('Entity Time',
StanzaPath('iq/entity_time'),
self._handle_time_request))
register_stanza_plugin(Iq, stanza.EntityTime)
def post_init(self):
"""Handle cross-plugin interactions."""
base_plugin.post_init(self)
self.xmpp['xep_0030'].add_feature('urn:xmpp:time')
def _handle_time_request(self, iq):
"""
Respond to a request for the local time.
The time is taken from self.local_time(), which may be replaced
during plugin configuration with a function that maps JIDs to
times.
Arguments:
iq -- The Iq time request stanza.
"""
iq.reply()
iq['entity_time']['time'] = self.local_time(iq['to'])
iq.send()
def get_entity_time(self, to, ifrom=None, **iqargs):
"""
Request the time from another entity.
Arguments:
to -- JID of the entity to query.
ifrom -- Specifiy the sender's JID.
block -- If true, block and wait for the stanzas' reply.
timeout -- The time in seconds to block while waiting for
a reply. If None, then wait indefinitely.
callback -- Optional callback to execute when a reply is
received instead of blocking and waiting for
the reply.
"""
iq = self.xmpp.Iq()
iq['type'] = 'get'
iq['to'] = 'to'
if ifrom:
iq['from'] = 'ifrom'
iq.enable('entity_time')
return iq.send(**iqargs)