commit 5ae9899ebe5251a46bae86ea3650ec337787dc85 Author: Damian Johnson atagar@torproject.org Date: Sun Dec 14 10:24:28 2014 -0800
Having create_hidden_service() provide a namedtuple
On reflection it's handy for this method to return more than just a maybe-read-maybe-not hostname. Instead providing back a namedtuple with the hidden service attributes. Extra advantage is that this can be used as a boolean to determine 'did we create or update a hidden service'. --- stem/control.py | 65 ++++++++++++++++++++++++-------------- test/integ/control/controller.py | 12 ++++--- 2 files changed, 48 insertions(+), 29 deletions(-)
diff --git a/stem/control.py b/stem/control.py index 77a5e3b..4d8b170 100644 --- a/stem/control.py +++ b/stem/control.py @@ -357,6 +357,12 @@ AccountingStats = collections.namedtuple('AccountingStats', [ 'write_limit', ])
+CreateHiddenServiceOutput = collections.namedtuple('CreateHiddenServiceOutput', [ + 'path', + 'hostname', + 'config', +]) +
def with_default(yields = False): """ @@ -2235,11 +2241,18 @@ class Controller(BaseController): def create_hidden_service(self, path, port, target_address = None, target_port = None): """ Create a new hidden service. If the directory is already present, a - new port is added. + new port is added. This provides a **namedtuple** of the following... + + * path (str) - hidden service directory
- This method returns our *.onion address by reading the hidden service - directory. However, this directory is only readable by the tor user, so if - unavailable this method returns None. + * hostname (str) - onion address of the service, this is only retrieved + if we can read the hidden service directory + + * config (dict) - tor's new hidden service configuration + + Our *.onion address is fetched by reading the hidden service directory. + However, this directory is only readable by the tor user, so if unavailable + the **hostname** will be **None**.
.. versionadded:: 1.3.0
@@ -2249,8 +2262,7 @@ class Controller(BaseController): :param int target_port: port of the service, by default this is the same as **port**
- :returns: **str** of the onion address for the hidden service if it can be - retrieved, **None** otherwise + :returns: **CreateHiddenServiceOutput** if we create or update a hidden service, **None** otherwise
:raises: :class:`stem.ControllerError` if the call fails """ @@ -2268,41 +2280,46 @@ class Controller(BaseController):
conf = self.get_hidden_service_conf()
- if path in conf: - ports = conf[path]['HiddenServicePort'] - - if (port, target_address, target_port) in ports: - return - else: - conf[path] = {'HiddenServicePort': []} + if path in conf and (port, target_address, target_port) in conf[path]['HiddenServicePort']: + return None
- conf[path]['HiddenServicePort'].append((port, target_address, target_port)) + conf.setdefault(path, OrderedDict()).setdefault('HiddenServicePort', []).append((port, target_address, target_port)) self.set_hidden_service_conf(conf)
+ hostname = None + if self.is_localhost(): - if not os.path.isabs(path): + hostname_path = os.path.join(path, 'hostname') + + if not os.path.isabs(hostname_path): cwd = stem.util.system.cwd(self.get_pid(None))
if cwd: - path = stem.util.system.expand_path(path, cwd) + hostname_path = stem.util.system.expand_path(hostname_path, cwd)
- if os.path.isabs(path): + if os.path.isabs(hostname_path): start_time = time.time() - hostname_path = os.path.join(path, 'hostname')
while not os.path.exists(hostname_path): wait_time = time.time() - start_time
if wait_time >= 3: - return + break else: time.sleep(0.05)
- try: - with open(hostname_path) as hostname_file: - return hostname_file.read().strip() - except: - pass + if os.path.exists(hostname_path): + try: + with open(hostname_path) as hostname_file: + hostname = hostname_file.read().strip() + except: + pass + + return CreateHiddenServiceOutput( + path = path, + hostname = hostname, + config = conf, + )
def remove_hidden_service(self, path, port = None): """ diff --git a/test/integ/control/controller.py b/test/integ/control/controller.py index 8b9759c..e482281 100644 --- a/test/integ/control/controller.py +++ b/test/integ/control/controller.py @@ -512,8 +512,8 @@ class TestController(unittest.TestCase): # add a new service, with/without explicit target
hs_path = os.path.join(os.getcwd(), 'test_hidden_serviceX') - hs_address1 = controller.create_hidden_service(hs_path, 8888) - hs_address2 = controller.create_hidden_service(hs_path, 8989, target_port = 8021) + hs_address1 = controller.create_hidden_service(hs_path, 8888).hostname + hs_address2 = controller.create_hidden_service(hs_path, 8989, target_port = 8021).hostname
self.assertEqual(hs_address1, hs_address2) self.assertTrue(hs_address1.endswith('.onion')) @@ -536,9 +536,11 @@ class TestController(unittest.TestCase):
# clean up the hidden service directories created as part of this test
- shutil.rmtree('test_hidden_service1') - shutil.rmtree('test_hidden_service2') - shutil.rmtree('test_hidden_serviceX') + for path in ('test_hidden_service1', 'test_hidden_service2', 'test_hidden_serviceX'): + try: + shutil.rmtree(path) + except: + pass
def test_set_conf(self): """
tor-commits@lists.torproject.org