|
|
@@ -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: |
|
|
|