2006-11-30 22:14:47 +00:00
|
|
|
|
2006-12-03 07:52:28 +00:00
|
|
|
import os, sha
|
2006-12-03 01:27:18 +00:00
|
|
|
from foolscap import Referenceable
|
2006-11-30 22:14:47 +00:00
|
|
|
from twisted.application import service
|
2006-11-30 22:27:06 +00:00
|
|
|
from twisted.python import log
|
2006-12-02 02:17:50 +00:00
|
|
|
from zope.interface import implements
|
|
|
|
from allmydata.interfaces import RIClient
|
2006-12-03 01:27:18 +00:00
|
|
|
from allmydata import node
|
2006-11-30 23:23:39 +00:00
|
|
|
|
2006-12-03 02:37:31 +00:00
|
|
|
from twisted.internet import defer
|
2006-11-30 22:14:47 +00:00
|
|
|
|
2006-12-04 02:07:41 +00:00
|
|
|
from allmydata.util import idlib
|
2006-12-01 03:14:23 +00:00
|
|
|
from allmydata.storageserver import StorageServer
|
2006-12-03 01:27:18 +00:00
|
|
|
from allmydata.upload import Uploader
|
2006-12-03 10:01:43 +00:00
|
|
|
from allmydata.download import Downloader
|
2006-12-04 02:07:41 +00:00
|
|
|
from allmydata.vdrive import VDrive
|
2006-11-30 22:29:52 +00:00
|
|
|
|
2006-12-03 01:27:18 +00:00
|
|
|
class Client(node.Node, Referenceable):
|
2006-12-02 02:17:50 +00:00
|
|
|
implements(RIClient)
|
2006-11-30 22:27:06 +00:00
|
|
|
CERTFILE = "client.pem"
|
2006-12-03 01:27:18 +00:00
|
|
|
PORTNUMFILE = "client.port"
|
2006-12-01 03:14:23 +00:00
|
|
|
STOREDIR = 'storage'
|
2006-12-03 01:27:18 +00:00
|
|
|
NODETYPE = "client"
|
2006-11-30 22:27:06 +00:00
|
|
|
|
2006-12-03 01:27:18 +00:00
|
|
|
def __init__(self, basedir="."):
|
|
|
|
node.Node.__init__(self, basedir)
|
2006-11-30 22:27:06 +00:00
|
|
|
self.queen = None # self.queen is either None or a RemoteReference
|
2006-12-01 01:09:57 +00:00
|
|
|
self.all_peers = set()
|
|
|
|
self.connections = {}
|
2006-12-03 07:52:28 +00:00
|
|
|
self.add_service(StorageServer(os.path.join(basedir, self.STOREDIR)))
|
2006-12-03 01:27:18 +00:00
|
|
|
self.add_service(Uploader())
|
2006-12-03 10:01:43 +00:00
|
|
|
self.add_service(Downloader())
|
2006-12-04 02:07:41 +00:00
|
|
|
self.add_service(VDrive())
|
2006-12-03 01:27:18 +00:00
|
|
|
self.queen_pburl = None
|
|
|
|
self.queen_connector = None
|
2006-12-03 02:37:31 +00:00
|
|
|
|
|
|
|
def tub_ready(self):
|
|
|
|
self.my_pburl = self.tub.registerReference(self)
|
|
|
|
self.maybe_connect_to_queen()
|
2006-11-30 23:23:39 +00:00
|
|
|
|
2006-12-03 01:27:18 +00:00
|
|
|
def set_queen_pburl(self, queen_pburl):
|
|
|
|
self.queen_pburl = queen_pburl
|
|
|
|
self.maybe_connect_to_queen()
|
2006-11-30 22:27:06 +00:00
|
|
|
|
2006-12-03 01:27:18 +00:00
|
|
|
def maybe_connect_to_queen(self):
|
|
|
|
if not self.running:
|
|
|
|
return
|
|
|
|
if not self.my_pburl:
|
|
|
|
return
|
|
|
|
if self.queen_connector:
|
|
|
|
return
|
|
|
|
if not self.queen_pburl:
|
2006-12-03 03:27:50 +00:00
|
|
|
self.log("no queen_pburl, cannot connect")
|
2006-12-03 01:27:18 +00:00
|
|
|
return
|
|
|
|
self.queen_connector = self.tub.connectTo(self.queen_pburl,
|
|
|
|
self._got_queen)
|
|
|
|
|
2006-11-30 22:27:06 +00:00
|
|
|
def stopService(self):
|
2006-12-03 01:27:18 +00:00
|
|
|
if self.queen_connector:
|
|
|
|
self.queen_connector.stopConnecting()
|
|
|
|
self.queen_connector = None
|
|
|
|
return service.MultiService.stopService(self)
|
2006-11-30 22:27:06 +00:00
|
|
|
|
|
|
|
def _got_queen(self, queen):
|
2006-12-03 03:27:50 +00:00
|
|
|
self.log("connected to queen")
|
2006-11-30 22:27:06 +00:00
|
|
|
self.queen = queen
|
|
|
|
queen.notifyOnDisconnect(self._lost_queen)
|
2006-12-04 02:07:41 +00:00
|
|
|
d = queen.callRemote("hello",
|
|
|
|
nodeid=self.nodeid,
|
|
|
|
node=self,
|
|
|
|
pburl=self.my_pburl)
|
|
|
|
d.addCallback(self._got_vdrive_root)
|
|
|
|
|
|
|
|
def _got_vdrive_root(self, root):
|
|
|
|
self.getServiceNamed("vdrive").set_root(root)
|
2006-11-30 22:27:06 +00:00
|
|
|
|
|
|
|
def _lost_queen(self):
|
2006-12-03 03:27:50 +00:00
|
|
|
self.log("lost connection to queen")
|
2006-11-30 22:27:06 +00:00
|
|
|
self.queen = None
|
2006-12-01 01:09:57 +00:00
|
|
|
|
|
|
|
def remote_get_service(self, name):
|
2006-12-04 02:07:41 +00:00
|
|
|
# TODO: 'vdrive' should not be public in the medium term
|
2006-12-01 01:09:57 +00:00
|
|
|
return self.getServiceNamed(name)
|
|
|
|
|
|
|
|
def remote_add_peers(self, new_peers):
|
|
|
|
for nodeid, pburl in new_peers:
|
2006-12-01 02:20:17 +00:00
|
|
|
if nodeid == self.nodeid:
|
2006-12-01 01:09:57 +00:00
|
|
|
continue
|
2006-12-03 03:27:50 +00:00
|
|
|
self.log("adding peer %s" % idlib.b2a(nodeid))
|
2006-12-01 01:09:57 +00:00
|
|
|
if nodeid in self.all_peers:
|
2006-12-03 03:29:09 +00:00
|
|
|
self.log("weird, I already had an entry for them")
|
|
|
|
return
|
2006-12-01 01:09:57 +00:00
|
|
|
self.all_peers.add(nodeid)
|
|
|
|
if nodeid not in self.connections:
|
|
|
|
d = self.tub.getReference(pburl)
|
2006-12-03 07:53:07 +00:00
|
|
|
def _got_reference(ref, which_nodeid):
|
|
|
|
self.log("connected to %s" % idlib.b2a(which_nodeid))
|
|
|
|
if which_nodeid in self.all_peers:
|
|
|
|
self.connections[which_nodeid] = ref
|
|
|
|
else:
|
|
|
|
log.msg(" ignoring it because we no longer want to talk to them")
|
|
|
|
d.addCallback(_got_reference, nodeid)
|
2006-12-01 01:09:57 +00:00
|
|
|
|
|
|
|
def remote_lost_peers(self, lost_peers):
|
|
|
|
for nodeid in lost_peers:
|
2006-12-03 03:27:50 +00:00
|
|
|
self.log("lost peer %s" % idlib.b2a(nodeid))
|
2006-12-01 01:09:57 +00:00
|
|
|
if nodeid in self.all_peers:
|
2006-12-01 01:13:46 +00:00
|
|
|
self.all_peers.remove(nodeid)
|
2006-12-01 01:09:57 +00:00
|
|
|
else:
|
2006-12-03 03:27:50 +00:00
|
|
|
self.log("weird, I didn't have an entry for them")
|
2006-12-01 01:09:57 +00:00
|
|
|
if nodeid in self.connections:
|
|
|
|
del self.connections[nodeid]
|
2006-12-01 01:17:36 +00:00
|
|
|
|
|
|
|
def get_remote_service(self, nodeid, servicename):
|
|
|
|
if nodeid not in self.connections:
|
2006-12-01 09:54:28 +00:00
|
|
|
return defer.fail(IndexError("no connection to that peer"))
|
2006-12-03 03:29:09 +00:00
|
|
|
peer = self.connections[nodeid]
|
|
|
|
d = peer.callRemote("get_service", name=servicename)
|
2006-12-01 01:17:36 +00:00
|
|
|
return d
|
2006-12-01 03:18:51 +00:00
|
|
|
|
|
|
|
|
|
|
|
def permute_peerids(self, key, max_count=None):
|
|
|
|
# TODO: eventually reduce memory consumption by doing an insertion
|
|
|
|
# sort of at most max_count elements
|
|
|
|
results = []
|
|
|
|
for nodeid in self.all_peers:
|
|
|
|
permuted = sha.new(key + nodeid).digest()
|
|
|
|
results.append((permuted, nodeid))
|
|
|
|
results.sort()
|
|
|
|
results = [r[1] for r in results]
|
|
|
|
if max_count is None:
|
|
|
|
return results
|
|
|
|
return results[:max_count]
|