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 threading import Timer
|
||||||
from group import Group
|
from group import Group
|
||||||
from bot import Bot
|
from bot import Bot
|
||||||
|
import deferred
|
||||||
from yowsupwrapper import YowsupApp
|
from yowsupwrapper import YowsupApp
|
||||||
|
from functools import partial
|
||||||
|
|
||||||
|
|
||||||
class MsgIDs:
|
class MsgIDs:
|
||||||
|
@ -723,23 +725,34 @@ class Session(YowsupApp):
|
||||||
self.buddies.remove(buddy)
|
self.buddies.remove(buddy)
|
||||||
|
|
||||||
def requestVCard(self, buddy, ID=None):
|
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]:
|
if buddy == self.user or buddy == self.user.split('@')[0]:
|
||||||
newbuddy = self.legacyName
|
buddy = self.legacyName
|
||||||
else:
|
|
||||||
newbuddy = buddy
|
# Get profile picture
|
||||||
self.logger.debug('Requesting profile picture of %s', newbuddy)
|
self.logger.debug('Requesting profile picture of %s', buddy)
|
||||||
self.requestProfilePicture(newbuddy, onSuccess = onSuccess)
|
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):
|
def onDlsuccess(self, path):
|
||||||
self.logger.info("Success: Image downloaded to %s", path)
|
self.logger.info("Success: Image downloaded to %s", path)
|
||||||
|
|
Loading…
Reference in a new issue