move upload/download interfaces to allmydata.interfaces, let SubTreeMaker assert IDownloader-ness of its 'downloader' argument

This commit is contained in:
Brian Warner 2007-01-21 15:01:34 -07:00
parent a8ecaf45b6
commit 430b3a03fc
6 changed files with 60 additions and 45 deletions

View File

@ -1,6 +1,6 @@
import os, sha import os, sha
from zope.interface import Interface, implements from zope.interface import implements
from twisted.python import failure, log from twisted.python import failure, log
from twisted.internet import defer from twisted.internet import defer
from twisted.application import service from twisted.application import service
@ -9,6 +9,7 @@ from allmydata.util import idlib, bencode
from allmydata.util.deferredutil import DeferredListShouldSucceed from allmydata.util.deferredutil import DeferredListShouldSucceed
from allmydata import codec from allmydata import codec
from allmydata.uri import unpack_uri from allmydata.uri import unpack_uri
from allmydata.interfaces import IDownloadTarget, IDownloader
class NotEnoughPeersError(Exception): class NotEnoughPeersError(Exception):
pass pass
@ -147,26 +148,6 @@ class FileDownloader:
def netstring(s): def netstring(s):
return "%d:%s," % (len(s), s) return "%d:%s," % (len(s), s)
class IDownloadTarget(Interface):
def open():
"""Called before any calls to write() or close()."""
def write(data):
pass
def close():
pass
def fail():
"""fail() is called to indicate that the download has failed. No
further methods will be invoked on the IDownloadTarget after fail()."""
def register_canceller(cb):
"""The FileDownloader uses this to register a no-argument function
that the target can call to cancel the download. Once this canceller
is invoked, no further calls to write() or close() will be made."""
def finish(self):
"""When the FileDownloader is done, this finish() function will be
called. Whatever it returns will be returned to the invoker of
Downloader.download.
"""
class FileName: class FileName:
implements(IDownloadTarget) implements(IDownloadTarget)
def __init__(self, filename): def __init__(self, filename):
@ -222,10 +203,6 @@ class FileHandle:
def finish(self): def finish(self):
pass pass
class IDownloader(Interface):
def download(uri, target):
pass
class Downloader(service.MultiService): class Downloader(service.MultiService):
"""I am a service that allows file downloading. """I am a service that allows file downloading.
""" """

View File

@ -9,6 +9,7 @@ from allmydata.filetree.interfaces import (
PathDoesNotExistError, PathDoesNotExistError,
) )
from allmydata.upload import IUploadable from allmydata.upload import IUploadable
from allmydata.interfaces import IDownloader
from allmydata.filetree.nodemaker import NodeMaker from allmydata.filetree.nodemaker import NodeMaker
@ -30,6 +31,7 @@ class SubTreeMaker(object):
# create subtrees. That means a Downloader and a reference to the # create subtrees. That means a Downloader and a reference to the
# queen. # queen.
self._queen = queen self._queen = queen
assert IDownloader(downloader)
self._downloader = downloader self._downloader = downloader
self._node_maker = NodeMaker() self._node_maker = NodeMaker()
self._cache = {} self._cache = {}

View File

@ -180,3 +180,46 @@ class ICodecDecoder(Interface):
of 'required_shares' passed into the original of 'required_shares' passed into the original
ICodecEncode.set_params() call. ICodecEncode.set_params() call.
""" """
class IDownloadTarget(Interface):
def open():
"""Called before any calls to write() or close()."""
def write(data):
"""Output some data to the target."""
def close():
"""Inform the target that there is no more data to be written."""
def fail():
"""fail() is called to indicate that the download has failed. No
further methods will be invoked on the IDownloadTarget after fail()."""
def register_canceller(cb):
"""The FileDownloader uses this to register a no-argument function
that the target can call to cancel the download. Once this canceller
is invoked, no further calls to write() or close() will be made."""
def finish(self):
"""When the FileDownloader is done, this finish() function will be
called. Whatever it returns will be returned to the invoker of
Downloader.download.
"""
class IDownloader(Interface):
def download(uri, target):
"""Perform a CHK download, sending the data to the given target.
'target' must provide IDownloadTarget."""
class IUploadable(Interface):
def get_filehandle():
"""Return a filehandle from which the data to be uploaded can be
read. It must implement .read, .seek, and .tell (since the latter two
are used to determine the length of the data)."""
def close_filehandle(f):
"""The upload is finished. This provides the same filehandle as was
returned by get_filehandle. This is an appropriate place to close the
filehandle."""
class IUploader(Interface):
def upload(uploadable):
"""Upload the file. 'uploadable' must impement IUploadable. This
returns a Deferred which fires with the URI of the file."""
def upload_ssk(write_capability, new_version, uploadable):
pass # TODO

View File

@ -1,8 +1,8 @@
#from zope.interface import implements from zope.interface import implements
from twisted.trial import unittest from twisted.trial import unittest
from twisted.internet import defer from twisted.internet import defer
#from allmydata.filetree.interfaces import IOpener, IDirectoryNode from allmydata.interfaces import IDownloader, IUploader
#from allmydata.filetree.directory import (ImmutableDirectorySubTree, #from allmydata.filetree.directory import (ImmutableDirectorySubTree,
# SubTreeNode, # SubTreeNode,
# CHKDirectorySubTree) # CHKDirectorySubTree)
@ -20,6 +20,7 @@ class FakeOpener(object):
#print "open", subtree_specification, subtree_specification.serialize(), parent_is_mutable #print "open", subtree_specification, subtree_specification.serialize(), parent_is_mutable
return defer.succeed(self.objects[subtree_specification.serialize()]) return defer.succeed(self.objects[subtree_specification.serialize()])
class FakeWorkQueue(object): class FakeWorkQueue(object):
implements(workqueue.IWorkQueue) implements(workqueue.IWorkQueue)
def __init__(self): def __init__(self):
@ -319,6 +320,7 @@ from allmydata.filetree.interfaces import (ISubTree, INode, IDirectoryNode,
IFileNode, NoSuchDirectoryError, IFileNode, NoSuchDirectoryError,
NoSuchChildError) NoSuchChildError)
from allmydata.filetree.file import CHKFileNode from allmydata.filetree.file import CHKFileNode
from allmydata.interfaces import IDownloader
from allmydata.util import bencode from allmydata.util import bencode
class InPairs(unittest.TestCase): class InPairs(unittest.TestCase):
@ -327,11 +329,14 @@ class InPairs(unittest.TestCase):
pairs = list(directory.in_pairs(l)) pairs = list(directory.in_pairs(l))
self.failUnlessEqual(pairs, [(0,1), (2,3), (4,5), (6,7)]) self.failUnlessEqual(pairs, [(0,1), (2,3), (4,5), (6,7)])
class StubDownloader(object):
implements(IDownloader)
class Stuff(unittest.TestCase): class Stuff(unittest.TestCase):
def makeVirtualDrive(self, basedir, root_node=None): def makeVirtualDrive(self, basedir, root_node=None):
wq = workqueue.WorkQueue(os.path.join(basedir, "1.workqueue")) wq = workqueue.WorkQueue(os.path.join(basedir, "1.workqueue"))
dl = None dl = StubDownloader()
if not root_node: if not root_node:
root_node = directory.LocalFileSubTreeNode() root_node = directory.LocalFileSubTreeNode()
root_node.new("rootdirtree.save") root_node.new("rootdirtree.save")
@ -347,7 +352,7 @@ class Stuff(unittest.TestCase):
self.failUnlessEqual(c1a, c2a) self.failUnlessEqual(c1a, c2a)
def testDirectory(self): def testDirectory(self):
stm = vdrive.SubTreeMaker(None, None) stm = vdrive.SubTreeMaker(None, StubDownloader())
# create an empty directory (stored locally) # create an empty directory (stored locally)
subtree = directory.LocalFileSubTree() subtree = directory.LocalFileSubTree()

View File

@ -1,5 +1,5 @@
from zope.interface import Interface, implements from zope.interface import implements
from twisted.python import failure, log from twisted.python import failure, log
from twisted.internet import defer from twisted.internet import defer
from twisted.application import service from twisted.application import service
@ -10,6 +10,7 @@ from allmydata.util.idlib import peerid_to_short_string as shortid
from allmydata.util.deferredutil import DeferredListShouldSucceed from allmydata.util.deferredutil import DeferredListShouldSucceed
from allmydata import codec from allmydata import codec
from allmydata.uri import pack_uri from allmydata.uri import pack_uri
from allmydata.interfaces import IUploadable, IUploader
from cStringIO import StringIO from cStringIO import StringIO
import sha import sha
@ -245,12 +246,6 @@ class FileUploader:
def netstring(s): def netstring(s):
return "%d:%s," % (len(s), s) return "%d:%s," % (len(s), s)
class IUploadable(Interface):
def get_filehandle():
pass
def close_filehandle(f):
pass
class FileName: class FileName:
implements(IUploadable) implements(IUploadable)
def __init__(self, filename): def __init__(self, filename):
@ -279,17 +274,10 @@ class FileHandle:
# the originator of the filehandle reserves the right to close it # the originator of the filehandle reserves the right to close it
pass pass
class IUploader(Interface):
def upload(uploadable):
"""Upload the file. 'uploadable' must impement IUploadable. This
returns a Deferred which fires with the URI of the file."""
def upload_ssk(write_capability, new_version, uploadable):
pass # TODO
class Uploader(service.MultiService): class Uploader(service.MultiService):
"""I am a service that allows file uploading. """I am a service that allows file uploading.
""" """
implements(IUploader)
name = "uploader" name = "uploader"
uploader_class = FileUploader uploader_class = FileUploader
debug = False debug = False

View File

@ -4,7 +4,7 @@ from twisted.web import static, resource, server, html
from twisted.python import util, log from twisted.python import util, log
from nevow import inevow, rend, loaders, appserver, url, tags as T from nevow import inevow, rend, loaders, appserver, url, tags as T
from allmydata.util import idlib from allmydata.util import idlib
from allmydata.download import IDownloadTarget#, IDownloader from allmydata.interfaces import IDownloadTarget#, IDownloader
from allmydata import upload from allmydata import upload
from zope.interface import implements, Interface from zope.interface import implements, Interface
import urllib import urllib