Add Deferreds
This commit is contained in:
parent
5fb84bca4f
commit
03e56a4c07
97
deferred.py
Normal file
97
deferred.py
Normal file
|
@ -0,0 +1,97 @@
|
|||
class Deferred(object):
|
||||
"""
|
||||
Represents a delayed computation. This is a more elegant way to deal with
|
||||
callbacks.
|
||||
|
||||
A Deferred object can be thought of as a computation whose value is yet to
|
||||
be determined. We can manipulate the Deferred as if it where a regular
|
||||
value by using the then method. Computations dependent on the Deferred will
|
||||
only proceed when the run method is called.
|
||||
|
||||
Attributes of a Deferred can be accessed directly as methods.
|
||||
|
||||
Example:
|
||||
image = Deferred()
|
||||
getImageWithCallback(image.run)
|
||||
image.then(displayFunc)
|
||||
|
||||
colors = Deferred()
|
||||
colors.append('blue')
|
||||
colors.then(print)
|
||||
colors.run(['red', 'green']) #=> ['red', 'green', 'blue']
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.subscribers = []
|
||||
self.computed = False
|
||||
self.args = None
|
||||
self.kwargs = None
|
||||
|
||||
def run(self, *args, **kwargs):
|
||||
"""
|
||||
Give a value to the deferred. Calling this method more than once will
|
||||
result in a DeferredHasValue exception to be raised.
|
||||
"""
|
||||
if self.computed:
|
||||
raise DeferredHasValue("Deferred object already has a value.")
|
||||
else:
|
||||
self.args = args
|
||||
self.kwargs = kwargs
|
||||
for func, deferred in self.subscribers:
|
||||
deferred.run(func(*args, **kwargs))
|
||||
self.computed = True
|
||||
|
||||
def then(self, func):
|
||||
"""
|
||||
Apply func to Deferred value. Returns a Deferred whose value will be
|
||||
the result of applying func.
|
||||
"""
|
||||
result = Deferred()
|
||||
if self.computed:
|
||||
result.run(func(*self.args, **self.kwargs))
|
||||
else:
|
||||
self.subscribers.append((func, result))
|
||||
return result
|
||||
|
||||
def arg(self, n):
|
||||
"""
|
||||
Returns the nth positional argument of a deferred as a deferred
|
||||
|
||||
Args:
|
||||
n - the index of the positional argument
|
||||
"""
|
||||
def helper(*args, **kwargs):
|
||||
return args[n]
|
||||
return self.then(helper)
|
||||
|
||||
def __getattr__(self, method_name):
|
||||
return getattr(Then(self), method_name)
|
||||
|
||||
|
||||
class Then(object):
|
||||
"""
|
||||
Allows you to call methods on a Deferred.
|
||||
|
||||
Example:
|
||||
colors = Deferred()
|
||||
Then(colors).append('blue')
|
||||
colors.run(['red', 'green'])
|
||||
colors.then(print) #=> ['red', 'green', 'blue']
|
||||
"""
|
||||
def __init__(self, deferred):
|
||||
self.deferred = deferred
|
||||
|
||||
def __getattr__(self, name):
|
||||
def tryCall(obj, *args, **kwargs):
|
||||
if callable(obj):
|
||||
return obj(*args, **kwargs)
|
||||
else:
|
||||
return obj
|
||||
def helper(*args, **kwargs):
|
||||
func = (lambda x: tryCall(getattr(x, name), *args, **kwargs))
|
||||
return self.deferred.then(func)
|
||||
return helper
|
||||
|
||||
class DeferredHasValue(Exception):
|
||||
def __init__(self, string):
|
||||
super(DeferredHasValue, self).__init__(string)
|
45
session.py
45
session.py
|
@ -39,7 +39,9 @@ from buddy import BuddyList
|
|||
from threading import Timer
|
||||
from group import Group
|
||||
from bot import Bot
|
||||
import deferred
|
||||
from yowsupwrapper import YowsupApp
|
||||
from functools import partial
|
||||
|
||||
|
||||
class MsgIDs:
|
||||
|
@ -723,23 +725,34 @@ class Session(YowsupApp):
|
|||
self.buddies.remove(buddy)
|
||||
|
||||
def requestVCard(self, buddy, ID=None):
|
||||
def onSuccess(response, request):
|
||||
self.logger.debug('Sending VCard (%s) with image id %s',
|
||||
ID, response.pictureId)
|
||||
image_hash = utils.sha1hash(response.pictureData)
|
||||
self.logger.debug('Image hash is %s', image_hash)
|
||||
if ID != None:
|
||||
self.backend.handleVCard(self.user, ID, buddy, "", "", response.pictureData)
|
||||
if not (buddy == self.user or buddy == self.user.split('@')[0]):
|
||||
obuddy = self.buddies[buddy]
|
||||
self.updateBuddy(buddy, obuddy.nick, obuddy.groups, image_hash)
|
||||
|
||||
if buddy == self.user or buddy == self.user.split('@')[0]:
|
||||
newbuddy = self.legacyName
|
||||
else:
|
||||
newbuddy = buddy
|
||||
self.logger.debug('Requesting profile picture of %s', newbuddy)
|
||||
self.requestProfilePicture(newbuddy, onSuccess = onSuccess)
|
||||
buddy = self.legacyName
|
||||
|
||||
# Get profile picture
|
||||
self.logger.debug('Requesting profile picture of %s', buddy)
|
||||
response = deferred.Deferred()
|
||||
self.requestProfilePicture(buddy, onSuccess = response.run)
|
||||
response = response.arg(0)
|
||||
|
||||
# Send VCard
|
||||
if ID != None:
|
||||
response.pictureId().then(partial(
|
||||
self.logger.debug, 'Sending VCard (%s) with image id %s', ID
|
||||
))
|
||||
pictureData = response.pictureData()
|
||||
response.pictureData().then(partial(
|
||||
self.backend.handleVCard, self.user, ID, buddy, "", ""
|
||||
))
|
||||
|
||||
# Send image hash
|
||||
if not buddy == self.legacyName:
|
||||
obuddy = self.buddies[buddy]
|
||||
image_hash = pictureData.then(utils.sha1hash)
|
||||
image_hash.then(partial(self.logger.debug, 'Image hash is %s'))
|
||||
image_hash.then(partial(
|
||||
self.updateBuddy, buddy, obuddy.nick, obuddy.groups
|
||||
))
|
||||
|
||||
|
||||
def onDlsuccess(self, path):
|
||||
self.logger.info("Success: Image downloaded to %s", path)
|
||||
|
|
Loading…
Reference in a new issue