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

@ -1,6 +1,6 @@
import os, sha
from zope.interface import Interface, implements
from zope.interface import implements
from twisted.python import failure, log
from twisted.internet import defer
from twisted.application import service
@ -9,6 +9,7 @@ from allmydata.util import idlib, bencode
from allmydata.util.deferredutil import DeferredListShouldSucceed
from allmydata import codec
from allmydata.uri import unpack_uri
from allmydata.interfaces import IDownloadTarget, IDownloader
class NotEnoughPeersError(Exception):
pass
@ -147,26 +148,6 @@ class FileDownloader:
def netstring(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:
implements(IDownloadTarget)
def __init__(self, filename):
@ -222,10 +203,6 @@ class FileHandle:
def finish(self):
pass
class IDownloader(Interface):
def download(uri, target):
pass
class Downloader(service.MultiService):
"""I am a service that allows file downloading.
"""

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

@ -180,3 +180,46 @@ class ICodecDecoder(Interface):
of 'required_shares' passed into the original
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

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

@ -1,5 +1,5 @@
from zope.interface import Interface, implements
from zope.interface import implements
from twisted.python import failure, log
from twisted.internet import defer
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 import codec
from allmydata.uri import pack_uri
from allmydata.interfaces import IUploadable, IUploader
from cStringIO import StringIO
import sha
@ -245,12 +246,6 @@ class FileUploader:
def netstring(s):
return "%d:%s," % (len(s), s)
class IUploadable(Interface):
def get_filehandle():
pass
def close_filehandle(f):
pass
class FileName:
implements(IUploadable)
def __init__(self, filename):
@ -279,17 +274,10 @@ class FileHandle:
# the originator of the filehandle reserves the right to close it
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):
"""I am a service that allows file uploading.
"""
implements(IUploader)
name = "uploader"
uploader_class = FileUploader
debug = False

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