2 import os, sha, stat, time
3 from foolscap import Referenceable, SturdyRef
4 from zope.interface import implements
5 from allmydata.interfaces import RIClient
6 from allmydata import node
8 from twisted.internet import defer, reactor
9 from twisted.application.internet import TimerService
12 from allmydata.Crypto.Util.number import bytes_to_long
13 from allmydata.storageserver import StorageServer
14 from allmydata.upload import Uploader
15 from allmydata.download import Downloader
16 from allmydata.vdrive import VDrive
17 from allmydata.webish import WebishServer
18 from allmydata.control import ControlServer
19 from allmydata.introducer import IntroducerClient
21 class Client(node.Node, Referenceable):
23 PORTNUMFILE = "client.port"
26 WEBPORTFILE = "webport"
27 INTRODUCER_FURL_FILE = "introducer.furl"
28 GLOBAL_VDRIVE_FURL_FILE = "vdrive.furl"
29 MY_FURL_FILE = "myself.furl"
30 SUICIDE_PREVENTION_HOTLINE_FILE = "suicide_prevention_hotline"
32 # we're pretty narrow-minded right now
33 OLDEST_SUPPORTED_VERSION = allmydata.__version__
35 def __init__(self, basedir="."):
36 node.Node.__init__(self, basedir)
38 self.introducer_client = None
39 self.connected_to_vdrive = False
40 self.add_service(StorageServer(os.path.join(basedir, self.STOREDIR)))
41 self.add_service(Uploader())
42 self.add_service(Downloader())
43 WEBPORTFILE = os.path.join(self.basedir, self.WEBPORTFILE)
44 if os.path.exists(WEBPORTFILE):
45 f = open(WEBPORTFILE, "r")
46 webport = f.read().strip() # strports string
48 self.add_service(WebishServer(webport))
50 INTRODUCER_FURL_FILE = os.path.join(self.basedir,
51 self.INTRODUCER_FURL_FILE)
52 f = open(INTRODUCER_FURL_FILE, "r")
53 self.introducer_furl = f.read().strip()
56 self.global_vdrive_furl = None
57 GLOBAL_VDRIVE_FURL_FILE = os.path.join(self.basedir,
58 self.GLOBAL_VDRIVE_FURL_FILE)
59 if os.path.exists(GLOBAL_VDRIVE_FURL_FILE):
60 f = open(GLOBAL_VDRIVE_FURL_FILE, "r")
61 self.global_vdrive_furl = f.read().strip()
63 self.add_service(VDrive())
65 hotline_file = os.path.join(self.basedir,
66 self.SUICIDE_PREVENTION_HOTLINE_FILE)
67 if os.path.exists(hotline_file):
68 hotline = TimerService(1.0, self._check_hotline, hotline_file)
69 hotline.setServiceParent(self)
71 def _check_hotline(self, hotline_file):
72 if os.path.exists(hotline_file):
73 mtime = os.stat(hotline_file)[stat.ST_MTIME]
74 if mtime > time.time() - 10.0:
76 self.log("hotline missing or too old, shutting down")
83 MYSELF_FURL_PATH = os.path.join(self.basedir, self.MY_FURL_FILE)
84 if os.path.exists(MYSELF_FURL_PATH):
85 my_old_furl = open(MYSELF_FURL_PATH, "r").read().strip()
86 sturdy = SturdyRef(my_old_furl)
87 my_old_name = sturdy.name
89 self.my_furl = self.tub.registerReference(self, my_old_name)
90 f = open(MYSELF_FURL_PATH, "w")
94 ic = IntroducerClient(self.tub, self.introducer_furl, self.my_furl)
95 self.introducer_client = ic
96 ic.setServiceParent(self)
98 self.register_control()
100 if self.global_vdrive_furl:
101 self.vdrive_connector = self.tub.connectTo(self.global_vdrive_furl,
104 def register_control(self):
106 c.setServiceParent(self)
107 control_url = self.tub.registerReference(c)
108 f = open("control.furl", "w")
109 f.write(control_url + "\n")
111 os.chmod("control.furl", 0600)
113 def _got_vdrive(self, vdrive_root):
114 # vdrive_root implements RIMutableDirectoryNode
115 self.log("connected to vdrive")
116 self.connected_to_vdrive = True
117 self.getServiceNamed("vdrive").set_root(vdrive_root)
118 if "webish" in self.namedServices:
119 self.getServiceNamed("webish").set_root_dirnode(vdrive_root)
121 self.connected_to_vdrive = False
122 vdrive_root.notifyOnDisconnect(_disconnected)
124 def remote_get_versions(self):
125 return str(allmydata.__version__), str(self.OLDEST_SUPPORTED_VERSION)
127 def remote_get_service(self, name):
128 # TODO: 'vdrive' should not be public in the medium term
129 return self.getServiceNamed(name)
131 def get_remote_service(self, nodeid, servicename):
132 if nodeid not in self.introducer_client.connections:
133 return defer.fail(IndexError("no connection to that peer"))
134 peer = self.introducer_client.connections[nodeid]
135 d = peer.callRemote("get_service", name=servicename)
139 def get_all_peerids(self):
140 return self.introducer_client.connections.iterkeys()
142 def get_permuted_peers(self, key):
144 @return: list of (permuted-peerid, peerid, connection,)
147 for peerid, connection in self.introducer_client.connections.iteritems():
148 assert isinstance(peerid, str)
149 permuted = bytes_to_long(sha.new(key + peerid).digest())
150 results.append((permuted, peerid, connection))