]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/blob - src/allmydata/client.py
f25ed962a40795ae4b3a833bce698a0ada87c9f5
[tahoe-lafs/tahoe-lafs.git] / src / allmydata / client.py
1
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
7
8 from twisted.internet import defer, reactor
9 from twisted.application.internet import TimerService
10
11 import allmydata
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
20
21 class Client(node.Node, Referenceable):
22     implements(RIClient)
23     PORTNUMFILE = "client.port"
24     STOREDIR = 'storage'
25     NODETYPE = "client"
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"
31
32     # we're pretty narrow-minded right now
33     OLDEST_SUPPORTED_VERSION = allmydata.__version__
34
35     def __init__(self, basedir="."):
36         node.Node.__init__(self, basedir)
37         self.my_furl = None
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
47             f.close()
48             self.add_service(WebishServer(webport))
49
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()
54         f.close()
55
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()
62             f.close()
63             self.add_service(VDrive())
64
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)
70
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:
75                 return
76         self.log("hotline missing or too old, shutting down")
77         reactor.stop()
78
79     def tub_ready(self):
80         self.log("tub_ready")
81
82         my_old_name = None
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
88
89         self.my_furl = self.tub.registerReference(self, my_old_name)
90         f = open(MYSELF_FURL_PATH, "w")
91         f.write(self.my_furl)
92         f.close()
93
94         ic = IntroducerClient(self.tub, self.introducer_furl, self.my_furl)
95         self.introducer_client = ic
96         ic.setServiceParent(self)
97
98         self.register_control()
99
100         if self.global_vdrive_furl:
101             self.vdrive_connector = self.tub.connectTo(self.global_vdrive_furl,
102                                                        self._got_vdrive)
103
104     def register_control(self):
105         c = ControlServer()
106         c.setServiceParent(self)
107         control_url = self.tub.registerReference(c)
108         f = open("control.furl", "w")
109         f.write(control_url + "\n")
110         f.close()
111         os.chmod("control.furl", 0600)
112
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)
120         def _disconnected():
121             self.connected_to_vdrive = False
122         vdrive_root.notifyOnDisconnect(_disconnected)
123
124     def remote_get_versions(self):
125         return str(allmydata.__version__), str(self.OLDEST_SUPPORTED_VERSION)
126
127     def remote_get_service(self, name):
128         # TODO: 'vdrive' should not be public in the medium term
129         return self.getServiceNamed(name)
130
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)
136         return d
137
138
139     def get_all_peerids(self):
140         return self.introducer_client.connections.iterkeys()
141
142     def get_permuted_peers(self, key):
143         """
144         @return: list of (permuted-peerid, peerid, connection,)
145         """
146         results = []
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))
151         results.sort()
152         return results