2008-06-18 19:24:16 +00:00
|
|
|
|
|
|
|
import time, os.path
|
|
|
|
from zope.interface import implements
|
|
|
|
from twisted.application import service
|
|
|
|
from foolscap import Referenceable
|
2008-11-22 00:43:52 +00:00
|
|
|
import allmydata
|
2008-06-18 19:24:16 +00:00
|
|
|
from allmydata import node
|
|
|
|
from allmydata.util import log
|
2008-06-19 00:04:41 +00:00
|
|
|
from allmydata.introducer.interfaces import \
|
|
|
|
RIIntroducerPublisherAndSubscriberService
|
2008-06-18 19:24:16 +00:00
|
|
|
from allmydata.introducer.common import make_index
|
|
|
|
|
|
|
|
class IntroducerNode(node.Node):
|
|
|
|
PORTNUMFILE = "introducer.port"
|
|
|
|
NODETYPE = "introducer"
|
|
|
|
|
|
|
|
def __init__(self, basedir="."):
|
|
|
|
node.Node.__init__(self, basedir)
|
2008-09-30 23:21:49 +00:00
|
|
|
self.read_config()
|
2008-06-18 19:24:16 +00:00
|
|
|
self.init_introducer()
|
2008-09-30 23:21:49 +00:00
|
|
|
webport = self.get_config("node", "web.port", None)
|
2008-06-18 19:24:16 +00:00
|
|
|
if webport:
|
|
|
|
self.init_web(webport) # strports string
|
|
|
|
|
|
|
|
def init_introducer(self):
|
|
|
|
introducerservice = IntroducerService(self.basedir)
|
|
|
|
self.add_service(introducerservice)
|
|
|
|
|
|
|
|
d = self.when_tub_ready()
|
|
|
|
def _publish(res):
|
|
|
|
self.introducer_url = self.tub.registerReference(introducerservice,
|
|
|
|
"introducer")
|
|
|
|
self.log(" introducer is at %s" % self.introducer_url)
|
|
|
|
self.write_config("introducer.furl", self.introducer_url + "\n")
|
|
|
|
d.addCallback(_publish)
|
2008-08-26 01:57:59 +00:00
|
|
|
d.addErrback(log.err, facility="tahoe.init",
|
|
|
|
level=log.BAD, umid="UaNs9A")
|
2008-06-18 19:24:16 +00:00
|
|
|
|
|
|
|
def init_web(self, webport):
|
|
|
|
self.log("init_web(webport=%s)", args=(webport,))
|
|
|
|
|
|
|
|
from allmydata.webish import IntroducerWebishServer
|
|
|
|
nodeurl_path = os.path.join(self.basedir, "node.url")
|
2009-02-20 19:15:54 +00:00
|
|
|
ws = IntroducerWebishServer(self, webport, nodeurl_path)
|
2008-06-18 19:24:16 +00:00
|
|
|
self.add_service(ws)
|
|
|
|
|
|
|
|
class IntroducerService(service.MultiService, Referenceable):
|
|
|
|
implements(RIIntroducerPublisherAndSubscriberService)
|
|
|
|
name = "introducer"
|
2008-11-22 00:43:52 +00:00
|
|
|
VERSION = { "http://allmydata.org/tahoe/protocols/introducer/v1":
|
|
|
|
{ },
|
versioning: include an "appname" in the application version string in the versioning protocol, and make that appname be controlled by setup.py
It is currently hardcoded in setup.py to be 'allmydata-tahoe'. Ticket #556 is to make it configurable by a runtime command-line argument to setup.py: "--appname=foo", but I suddenly wondered if we really wanted that and at the same time realized that we don't need that for tahoe-1.3.0 release, so this patch just hardcodes it in setup.py.
setup.py inspects a file named 'src/allmydata/_appname.py' and assert that it contains the string "__appname__ = 'allmydata-tahoe'", and creates it if it isn't already present. src/allmydata/__init__.py import _appname and reads __appname__ from it. The rest of the Python code imports allmydata and inspects "allmydata.__appname__", although actually every use it uses "allmydata.__full_version__" instead, where "allmydata.__full_version__" is created in src/allmydata/__init__.py to be:
__full_version__ = __appname + '-' + str(__version__).
All the code that emits an "application version string" when describing what version of a protocol it supports (introducer server, storage server, upload helper), or when describing itself in general (introducer client), usese allmydata.__full_version__.
This fixes ticket #556 at least well enough for tahoe-1.3.0 release.
2009-02-12 00:18:16 +00:00
|
|
|
"application-version": str(allmydata.__full_version__),
|
2008-11-22 00:43:52 +00:00
|
|
|
}
|
2008-06-18 19:24:16 +00:00
|
|
|
|
|
|
|
def __init__(self, basedir="."):
|
|
|
|
service.MultiService.__init__(self)
|
|
|
|
self.introducer_url = None
|
|
|
|
# 'index' is (tubid, service_name)
|
|
|
|
self._announcements = {} # dict of index -> (announcement, timestamp)
|
|
|
|
self._subscribers = {} # dict of (rref->timestamp) dicts
|
|
|
|
|
|
|
|
def log(self, *args, **kwargs):
|
|
|
|
if "facility" not in kwargs:
|
|
|
|
kwargs["facility"] = "tahoe.introducer"
|
|
|
|
return log.msg(*args, **kwargs)
|
|
|
|
|
|
|
|
def get_announcements(self):
|
|
|
|
return self._announcements
|
|
|
|
def get_subscribers(self):
|
|
|
|
return self._subscribers
|
|
|
|
|
2008-11-22 00:43:52 +00:00
|
|
|
def remote_get_version(self):
|
|
|
|
return self.VERSION
|
|
|
|
|
2008-06-18 19:24:16 +00:00
|
|
|
def remote_publish(self, announcement):
|
|
|
|
self.log("introducer: announcement published: %s" % (announcement,) )
|
|
|
|
index = make_index(announcement)
|
|
|
|
if index in self._announcements:
|
|
|
|
(old_announcement, timestamp) = self._announcements[index]
|
|
|
|
if old_announcement == announcement:
|
|
|
|
self.log("but we already knew it, ignoring", level=log.NOISY)
|
|
|
|
return
|
|
|
|
else:
|
|
|
|
self.log("old announcement being updated", level=log.NOISY)
|
|
|
|
self._announcements[index] = (announcement, time.time())
|
|
|
|
(furl, service_name, ri_name, nickname, ver, oldest) = announcement
|
|
|
|
for s in self._subscribers.get(service_name, []):
|
|
|
|
s.callRemote("announce", set([announcement]))
|
|
|
|
|
|
|
|
def remote_subscribe(self, subscriber, service_name):
|
|
|
|
self.log("introducer: subscription[%s] request at %s" % (service_name,
|
|
|
|
subscriber))
|
|
|
|
if service_name not in self._subscribers:
|
|
|
|
self._subscribers[service_name] = {}
|
|
|
|
subscribers = self._subscribers[service_name]
|
|
|
|
if subscriber in subscribers:
|
|
|
|
self.log("but they're already subscribed, ignoring",
|
|
|
|
level=log.UNUSUAL)
|
|
|
|
return
|
|
|
|
subscribers[subscriber] = time.time()
|
|
|
|
def _remove():
|
|
|
|
self.log("introducer: unsubscribing[%s] %s" % (service_name,
|
|
|
|
subscriber))
|
|
|
|
subscribers.pop(subscriber, None)
|
|
|
|
subscriber.notifyOnDisconnect(_remove)
|
|
|
|
|
|
|
|
announcements = set( [ ann
|
|
|
|
for idx,(ann,when) in self._announcements.items()
|
|
|
|
if idx[1] == service_name] )
|
|
|
|
d = subscriber.callRemote("announce", announcements)
|
|
|
|
d.addErrback(log.err, facility="tahoe.introducer", level=log.UNUSUAL)
|
|
|
|
|
|
|
|
|
|
|
|
|