[tor-commits] [stem/master] Adding get_effective_rate() to the Controller
atagar at torproject.org
atagar at torproject.org
Sun Sep 21 01:47:55 UTC 2014
commit 8ae878d48268ff38d232cc7c8e6ff40f8ec6324b
Author: Damian Johnson <atagar at torproject.org>
Date: Sat Sep 20 13:12:51 2014 -0700
Adding get_effective_rate() to the Controller
Method to provide the bytes per second we're configured to relay at. Tor has
this be the minimum of a few parameters so it's not as stright forward as
'gimme the GETCONF BandwidthRate'.
---
docs/change_log.rst | 1 +
stem/control.py | 42 +++++++++++++++++++++++++++++++++++++++
test/unit/control/controller.py | 23 +++++++++++++++++++++
3 files changed, 66 insertions(+)
diff --git a/docs/change_log.rst b/docs/change_log.rst
index c5867e4..7297cb9 100644
--- a/docs/change_log.rst
+++ b/docs/change_log.rst
@@ -43,6 +43,7 @@ The following are only available within Stem's `git repository
* **Controller**
* Added :func:`~stem.control.Controller.get_accounting_stats` to the :class:`~stem.control.Controller`
+ * Added :func:`~stem.control.Controller.get_effective_rate` to the :class:`~stem.control.Controller`
* Added :func:`~stem.control.BaseController.connection_time` to the :class:`~stem.control.BaseController`
* Changed :func:`~stem.control.Controller.get_microdescriptor`, :func:`~stem.control.Controller.get_server_descriptor`, and :func:`~stem.control.Controller.get_network_status` to get our own descriptor if no fingerprint or nickname is provided.
* Added :class:`~stem.exit_policy.ExitPolicy` methods for more easily handling 'private' policies (the `default prefix <https://www.torproject.org/docs/tor-manual.html.en#ExitPolicyRejectPrivate>`_) and the defaultly appended suffix. This includes :func:`~stem.exit_policy.ExitPolicy.has_private`, :func:`~stem.exit_policy.ExitPolicy.strip_private`, :func:`~stem.exit_policy.ExitPolicy.has_default`, and :func:`~stem.exit_policy.ExitPolicy.strip_default` :class:`~stem.exit_policy.ExitPolicy` methods in addition to :func:`~stem.exit_policy.ExitPolicyRule.is_private` and :func:`~stem.exit_policy.ExitPolicyRule.is_default` for the :class:`~stem.exit_policy.ExitPolicyRule`. (:trac:`10107`)
diff --git a/stem/control.py b/stem/control.py
index 04098c0..4688bd7 100644
--- a/stem/control.py
+++ b/stem/control.py
@@ -122,6 +122,7 @@ If you're fine with allowing your script to raise exceptions then this can be mo
|- signal - sends a signal to the tor client
|- is_newnym_available - true if tor would presently accept a NEWNYM signal
|- get_newnym_wait - seconds until tor would accept a NEWNYM signal
+ |- get_effective_rate - provides our effective relaying rate limit
|- is_geoip_unavailable - true if we've discovered our geoip db to be unavailable
|- map_address - maps one address to another such that connections to the original are replaced with the other
+- drop_guards - drops our set of guard relays and picks a new set
@@ -2666,6 +2667,47 @@ class Controller(BaseController):
return max(0.0, self._last_newnym + 10 - time.time())
+ def get_effective_rate(self, default = UNDEFINED, burst = False):
+ """
+ Provides the maximum rate this relay is configured to relay in bytes per
+ second. This is based on multiple torrc parameters if they're set...
+
+ * Effective Rate = min(BandwidthRate, RelayBandwidthRate, MaxAdvertisedBandwidth)
+ * Effective Burst = min(BandwidthBurst, RelayBandwidthBurst)
+
+ :param object default: response if the query fails
+ :param bool burst: provides the burst bandwidth, otherwise this provides
+ the standard rate
+
+ :returns: **int** with the effective bandwidth rate in bytes per second
+
+ :raises: :class:`stem.ControllerError` if the call fails and no default was
+ provided
+ """
+
+ if not burst:
+ attributes = ('BandwidthRate', 'RelayBandwidthRate', 'MaxAdvertisedBandwidth')
+ else:
+ attributes = ('BandwidthBurst', 'RelayBandwidthBurst')
+
+ value = None
+
+ for attr in attributes:
+ try:
+ attr_value = int(self.get_conf(attr))
+
+ if attr_value == 0 and attr.startswith('Relay'):
+ continue # RelayBandwidthRate and RelayBandwidthBurst default to zero
+
+ value = min(value, attr_value) if value else attr_value
+ except stem.ControllerError as exc:
+ if default == UNDEFINED:
+ raise exc
+ else:
+ return default
+
+ return value
+
def is_geoip_unavailable(self):
"""
Provides **True** if we've concluded hat our geoip database is unavailable,
diff --git a/test/unit/control/controller.py b/test/unit/control/controller.py
index 7c7911e..948068f 100644
--- a/test/unit/control/controller.py
+++ b/test/unit/control/controller.py
@@ -588,6 +588,29 @@ class TestControl(unittest.TestCase):
for test_input in malformed_inputs:
self.assertRaises(ProtocolError, _parse_circ_path, test_input)
+ @patch('stem.control.Controller.get_conf')
+ def test_get_effective_rate(self, get_conf_mock):
+ """
+ Exercise the get_effective_rate() method.
+ """
+
+ # check default if nothing was set
+
+ get_conf_mock.side_effect = lambda param, **kwargs: {
+ 'BandwidthRate': '1073741824',
+ 'BandwidthBurst': '1073741824',
+ 'RelayBandwidthRate': '0',
+ 'RelayBandwidthBurst': '0',
+ 'MaxAdvertisedBandwidth': '1073741824',
+ }[param]
+
+ self.assertEqual(1073741824, self.controller.get_effective_rate())
+ self.assertEqual(1073741824, self.controller.get_effective_rate(burst = True))
+
+ get_conf_mock.side_effect = ControllerError('nope, too bad')
+ self.assertRaises(ControllerError, self.controller.get_effective_rate)
+ self.assertEqual('my_default', self.controller.get_effective_rate('my_default'))
+
@patch('stem.control.Controller.get_version')
def test_drop_guards(self, get_version_mock):
"""
More information about the tor-commits
mailing list