Browse Source

add support for poor many's async... I don't want to tangle out

how to handle making Browse async, so I'll just restart the call
if a subfunction raises a Deferred object...  This should work
amazingly well... we may end up wrapping just the check/doUpdate
calls...

[git-p4: depot-paths = "//depot/": change = 823]
v0.3
John-Mark Gurney 18 years ago
parent
commit
410eb9f330
1 changed files with 57 additions and 0 deletions
  1. +57
    -0
      ContentDirectory.py

+ 57
- 0
ContentDirectory.py View File

@@ -29,9 +29,54 @@ from elementtree.ElementTree import Element, SubElement, tostring
from upnp import UPnPPublisher, errorCode
from DIDLLite import DIDLElement, Container, Movie, Resource, MusicTrack

from twisted.internet import defer
from twisted.python import failure

import traceback
from urllib import quote

class doRecall(defer.Deferred):
'''A class that will upon any callback from the Deferred object passed
in, recall fun(*args, **kwargs), just as if a maybeDeferred has been
processed.

The idea is to let something deeper called by something sync "abort"
the call until it's ready, and then reattempt. This isn't the best
method as we throw away work, but it can be easier to implement.

Example:
def wrapper(five):
try:
return doacall(five)
except defer.Deferred, x:
return doRecallgen(x, wrapper, five)

If doacall works, everything is fine, but if a Deferred object is
raised, we put it in a doRecall class and return the deferred object
generated by doRecall.'''

def __init__(self, argdef, fun, *args, **kwargs):
self.fun = fun
self.args = args
self.kwargs = kwargs
self.defer = defer.Deferred()

argdef.addCallback(self._done)

def _done(self, *args, **kwargs):
ret = self.fun(*self.args, **self.kwargs)
if isinstance(ret, failure.Failure):
self.defer.errback(ret)
elif isinstance(ret, defer.Deferred):
# We are fruther delayed, continue.
ret.addCallback(self._done)
else:
self.defer.callback(ret)

def doRecallgen(defer, fun, *args, **kwargs):
i = doRecall(defer, fun, *args, **kwargs)
return i.defer

class ContentDirectoryControl(UPnPPublisher, dict):
"""This class implements the CDS actions over SOAP."""

@@ -123,6 +168,12 @@ class ContentDirectoryControl(UPnPPublisher, dict):
BrowseFlags = ('BrowseMetaData', 'BrowseDirectChildren')

def soap_Browse(self, *args):
try:
return self.thereal_soap_Browse(*args)
except defer.Deferred, x:
return doRecallgen(x, self.soap_Browse, *args)

def thereal_soap_Browse(self, *args):
"""Required: Incrementally browse the native heirachy of the Content
Directory objects exposed by the Content Directory Service."""

@@ -151,8 +202,14 @@ class ContentDirectoryControl(UPnPPublisher, dict):
# filter out the ones that don't exist anymore, we need
# to check against None, since some dirs might be empty
# (of valid content) but exist.
# XXX - technically if list changed, we need to get
# some new ones by looping till we have a complete
# list.
ochup = filter(lambda x, s = self:
s[x.id].checkUpdate() is not None, ch)
# XXX - are we suppose to be calling addContainer
# for Containers instead of always addItem?
#log.msg('ochup:', `ochup`)
filter(lambda x, d = didl: d.addItem(x) and None, ochup)
total = len(self.getchildren(ObjectID))
else:


Loading…
Cancel
Save