commit a96ec510539f2918bf93c50d63ce68e919f71209 Author: Damian Johnson atagar@torproject.org Date: Sun Mar 6 13:55:21 2016 -0800
Shorthand functions for stem.descriptor.remote
Damn stem.descriptor.remote is useful! This has become our best method of fetching descriptors but its usage is a bit formulaic...
import stem.descriptor.remote
downloader = stem.descriptor.remote.DescriptorDownloader()
for desc in downloader.get_server_descriptors(): ... do stuff...
Why make users get a downloader object? It's useful for power users that need to customize how descriptors are downloaded, but 95% of users don't care. They simply want the bloody descriptors, so providing shorthand methods that do just that!
import stem.descriptor.remote
for desc in stem.descriptor.remote.get_server_descriptors(): ... do stuff... --- docs/_static/example/current_descriptors.py | 6 +- .../example/saving_and_loading_descriptors.py | 5 +- docs/_static/example/tor_descriptors.py | 7 +- docs/change_log.rst | 1 + stem/cached_tor_manual.cfg | 4 +- stem/descriptor/fallback_directories.cfg | 2 +- stem/descriptor/remote.py | 101 +++++++++++++++++++-- stem/settings.cfg | 1 + test/integ/descriptor/remote.py | 20 ++++ 9 files changed, 123 insertions(+), 24 deletions(-)
diff --git a/docs/_static/example/current_descriptors.py b/docs/_static/example/current_descriptors.py index f86b5b9..44c9ac3 100644 --- a/docs/_static/example/current_descriptors.py +++ b/docs/_static/example/current_descriptors.py @@ -1,9 +1,7 @@ -from stem.descriptor.remote import DescriptorDownloader - -downloader = DescriptorDownloader() +import stem.descriptor.remote
try: - for desc in downloader.get_consensus().run(): + for desc in stem.descriptor.remote.get_consensus().run(): print("found relay %s (%s)" % (desc.nickname, desc.fingerprint)) except Exception as exc: print("Unable to retrieve the consensus: %s" % exc) diff --git a/docs/_static/example/saving_and_loading_descriptors.py b/docs/_static/example/saving_and_loading_descriptors.py index bb2703e..42e3ffe 100644 --- a/docs/_static/example/saving_and_loading_descriptors.py +++ b/docs/_static/example/saving_and_loading_descriptors.py @@ -1,7 +1,6 @@ -from stem.descriptor.remote import DescriptorDownloader +import stem.descriptor.remote
-downloader = DescriptorDownloader() -server_descriptors = downloader.get_server_descriptors().run() +server_descriptors = stem.descriptor.remote.get_server_descriptors().run()
with open('/tmp/descriptor_dump', 'wb') as descriptor_file: descriptor_file.write(''.join(map(str, server_descriptors))) diff --git a/docs/_static/example/tor_descriptors.py b/docs/_static/example/tor_descriptors.py index 0ec0666..708e5fc 100644 --- a/docs/_static/example/tor_descriptors.py +++ b/docs/_static/example/tor_descriptors.py @@ -1,16 +1,15 @@ import sys
-from stem.descriptor.remote import DescriptorDownloader +import stem.descriptor.remote + from stem.util import str_tools
# provides a mapping of observed bandwidth to the relay nicknames def get_bw_to_relay(): bw_to_relay = {}
- downloader = DescriptorDownloader() - try: - for desc in downloader.get_server_descriptors().run(): + for desc in stem.descriptor.remote.get_server_descriptors().run(): if desc.exit_policy.is_exiting_allowed(): bw_to_relay.setdefault(desc.observed_bandwidth, []).append(desc.nickname) except Exception as exc: diff --git a/docs/change_log.rst b/docs/change_log.rst index 4f688aa..3ce6df2 100644 --- a/docs/change_log.rst +++ b/docs/change_log.rst @@ -59,6 +59,7 @@ The following are only available within Stem's `git repository
* **Descriptors**
+ * `Shorthand functions for stem.descriptor.remote <api/descriptor/remote.html#stem.descriptor.remote.get_instance>`_ * Added `fallback directory information <api/descriptor/remote.html#stem.descriptor.remote.FallbackDirectory>`_. * Lessened dirauth load of `stem.descriptor.remote <api/descriptor/remote.html>`_ by using fallback directories as well * Support for ed25519 descriptor fields (:spec:`5a79d67`) diff --git a/stem/cached_tor_manual.cfg b/stem/cached_tor_manual.cfg index a2dbaf7..e57167c 100644 --- a/stem/cached_tor_manual.cfg +++ b/stem/cached_tor_manual.cfg @@ -7,7 +7,7 @@ description | |By default, tor will only act as a client only. To help the network by providing bandwidth as a relay, change the ORPort configuration option -- see below. Please also consult the documentation on the Tor Project's website. man_commit af88e8f23742c810f478410fba60c43812dde85d -stem_commit 988aeb121b762f58712bda078d1f13ffa0819bfb +stem_commit 7fceffac0f988670f4fd6b5eb061b2ebeee9e560 commandline_options -f FILE => Specify a new configuration file to contain further Tor configuration options OR pass - to make Tor read its configuration from standard input. (Default: @CONFDIR@/torrc, or $HOME/.torrc if that file is not found) commandline_options --ignore-missing-torrc => Specifies that Tor should treat a missing torrc file as though it were empty. Ordinarily, Tor does this for missing default torrc files, but not for those specified on the command line. commandline_options --list-fingerprint => Generate your keys and output your nickname and fingerprint. @@ -1614,7 +1614,7 @@ config_options.TestingClientBootstrapConsensusMaxDownloadTries.description Try t config_options.TestingClientBootstrapConsensusAuthorityOnlyMaxDownloadTries.category Testing config_options.TestingClientBootstrapConsensusAuthorityOnlyMaxDownloadTries.name TestingClientBootstrapConsensusAuthorityOnlyMaxDownloadTries config_options.TestingClientBootstrapConsensusAuthorityOnlyMaxDownloadTries.usage NUM -config_options.TestingClientBootstrapConsensusAuthorityOnlyMaxDownloadTries.summary +config_options.TestingClientBootstrapConsensusAuthorityOnlyMaxDownloadTries.summary Number of times to attempt downloading consensus from authorities config_options.TestingClientBootstrapConsensusAuthorityOnlyMaxDownloadTries.description Try this many times to download a consensus while bootstrapping using authorities before giving up. Changing this requires that TestingTorNetwork is set. (Default: 4) config_options.TestingClientBootstrapConsensusMaxInProgressTries.category Testing config_options.TestingClientBootstrapConsensusMaxInProgressTries.name TestingClientBootstrapConsensusMaxInProgressTries diff --git a/stem/descriptor/fallback_directories.cfg b/stem/descriptor/fallback_directories.cfg index 91fd02a..faf6105 100644 --- a/stem/descriptor/fallback_directories.cfg +++ b/stem/descriptor/fallback_directories.cfg @@ -1,5 +1,5 @@ tor_commit e2202146d16af22502fd4166ac926fefa6528dff -stem_commit 988aeb121b762f58712bda078d1f13ffa0819bfb +stem_commit 7fceffac0f988670f4fd6b5eb061b2ebeee9e560 Doedel22.address 178.254.44.135 Doedel22.or_port 9001 Doedel22.dir_port 9030 diff --git a/stem/descriptor/remote.py b/stem/descriptor/remote.py index 13b49ab..1afa70a 100644 --- a/stem/descriptor/remote.py +++ b/stem/descriptor/remote.py @@ -3,9 +3,20 @@
""" Module for remotely retrieving descriptors from directory authorities and -mirrors. This is most easily done through the +mirrors. This is the simplest method for getting current tor descriptor +information... + +:: + + import stem.descriptor.remote + + for desc in stem.descriptor.remote.get_server_descriptors(): + if desc.exit_policy.is_exiting_allowed(): + print ' %s (%s)' % (desc.nickname, desc.fingerprint) + +More custom downloading behavior can be done through the :class:`~stem.descriptor.remote.DescriptorDownloader` class, which issues -:class:`~stem.descriptor.remote.Query` instances to get you the descriptor +:class:`~stem.descriptor.remote.Query` instances to get you descriptor content. For example...
:: @@ -31,16 +42,13 @@ content. For example... except Exception as exc: print 'Unable to retrieve the server descriptors: %s' % exc
-If you don't care about errors then you can also simply iterate over the query -itself... - ::
- for desc in downloader.get_server_descriptors(): - if desc.exit_policy.is_exiting_allowed(): - print ' %s (%s)' % (desc.nickname, desc.fingerprint) - -:: + get_instance - Provides a singleton DescriptorDownloader used for... + |- get_server_descriptors - provides present server descriptors + |- get_extrainfo_descriptors - provides present extrainfo descriptors + |- get_microdescriptors - provides present microdescriptors + +- get_consensus - provides the present consensus or router status entries
get_authorities - Provides tor directory information.
@@ -105,6 +113,79 @@ MAX_MICRODESCRIPTOR_HASHES = 92 GITWEB_FALLBACK_DIR_URL = 'https://gitweb.torproject.org/tor.git/plain/src/or/fallback_dirs.inc' CACHE_PATH = os.path.join(os.path.dirname(__file__), 'fallback_directories.cfg')
+SINGLETON_DOWNLOADER = None + + +def get_instance(): + """ + Provides the singleton :class:`~stem.descriptor.remote.DescriptorDownloader` + used for the following functions... + + * :func:`stem.descriptor.remote.get_server_descriptors` + * :func:`stem.descriptor.remote.get_extrainfo_descriptors` + * :func:`stem.descriptor.remote.get_microdescriptors` + * :func:`stem.descriptor.remote.get_consensus` + + .. versionadded:: 1.5.0 + + :returns: singleton :class:`~stem.descriptor.remote.DescriptorDownloader` instance + """ + + global SINGLETON_DOWNLOADER + + if SINGLETON_DOWNLOADER is None: + SINGLETON_DOWNLOADER = DescriptorDownloader() + + return SINGLETON_DOWNLOADER + + +def get_server_descriptors(fingerprints = None, **query_args): + """ + Shorthand for + :func:`~stem.descriptor.remote.DescriptorDownloader.get_server_descriptors` + on our singleton instance. + + .. versionadded:: 1.5.0 + """ + + return get_instance().get_server_descriptors(fingerprints, **query_args) + + +def get_extrainfo_descriptors(fingerprints = None, **query_args): + """ + Shorthand for + :func:`~stem.descriptor.remote.DescriptorDownloader.get_extrainfo_descriptors` + on our singleton instance. + + .. versionadded:: 1.5.0 + """ + + return get_instance().get_extrainfo_descriptors(fingerprints, **query_args) + + +def get_microdescriptors(hashes, **query_args): + """ + Shorthand for + :func:`~stem.descriptor.remote.DescriptorDownloader.get_microdescriptors` + on our singleton instance. + + .. versionadded:: 1.5.0 + """ + + return get_instance().get_microdescriptors(hashes, **query_args) + + +def get_consensus(authority_v3ident = None, **query_args): + """ + Shorthand for + :func:`~stem.descriptor.remote.DescriptorDownloader.get_consensus` + on our singleton instance. + + .. versionadded:: 1.5.0 + """ + + return get_instance().get_consensus(authority_v3ident, **query_args) +
def _guess_descriptor_type(resource): # Attempts to determine the descriptor type based on the resource url. This diff --git a/stem/settings.cfg b/stem/settings.cfg index cc90be6..6395a5d 100644 --- a/stem/settings.cfg +++ b/stem/settings.cfg @@ -341,6 +341,7 @@ manual.summary.TestingClientMaxIntervalWithoutRequest Maximum time to wait to ba manual.summary.TestingDirConnectionMaxStall Duration to let directory connections stall before timing out manual.summary.TestingConsensusMaxDownloadTries Retries for downloading the consensus manual.summary.TestingClientBootstrapConsensusMaxDownloadTries Number of times to attempt downloading consensus +manual.summary.TestingClientBootstrapConsensusAuthorityOnlyMaxDownloadTries Number of times to attempt downloading consensus from authorities manual.summary.TestingClientBootstrapConsensusMaxInProgressTries Number of consensus download requests to allow in-flight at once manual.summary.TestingDescriptorMaxDownloadTries Retries for downloading server descriptors manual.summary.TestingMicrodescMaxDownloadTries Retries for downloading microdescriptors diff --git a/test/integ/descriptor/remote.py b/test/integ/descriptor/remote.py index a73bb0e..ef556ae 100644 --- a/test/integ/descriptor/remote.py +++ b/test/integ/descriptor/remote.py @@ -22,6 +22,26 @@ from test.runner import ( class TestDescriptorDownloader(unittest.TestCase): @require_online @only_run_once + def test_shorthand_aliases(self): + """ + Quick sanity test that we can call our shorthand aliases for getting + descriptors. + """ + + desc = list(stem.descriptor.remote.get_server_descriptors('9695DFC35FFEB861329B9F1AB04C46397020CE31'))[0] + self.assertEqual('moria1', desc.nickname) + + desc = list(stem.descriptor.remote.get_extrainfo_descriptors('9695DFC35FFEB861329B9F1AB04C46397020CE31'))[0] + self.assertEqual('moria1', desc.nickname) + + desc = list(stem.descriptor.remote.get_microdescriptors('6dCl6ab8CLo0LeMjxi/MZgVJiZgWN8WKTesWPBMtyTo'))[0] + self.assertEqual('moria1', desc.digest) + + consensus = list(stem.descriptor.remote.get_consensus()) + self.assertTrue(len(consensus) > 50) + + @require_online + @only_run_once def test_authorities_are_up_to_date(self): """ Check that our hardcoded directory authority data matches the present
tor-commits@lists.torproject.org