[tor-dev] txtorcon: fixing APIs, painting bikesheds

meejah meejah at meejah.ca
Sun Apr 10 18:27:33 UTC 2016

There are several rough edges and "regrettable" API choices in txtorcon
that I'd like to fix as a "1.x" release. I also had several productive
discssions with Brian Warner (thanks a lot!) suggesting some things to
make using txtorcon easier.

To that end, I am collecting some of these thoughts as well as massively
re-organizing (re-doing?) the documentation in a branch called
"release-1.x". ReadTheDocs is building this now, too. Some highlights of
what I'm doing or find annoying currently:

 - Move a bunch of things to "private" attrs/functions that were never
   supposed to be public (i.e. prefix a bunch more things with "_")

 - Eliminate need to deal with the "bootstrap" Deferreds (via factory
   functions and/or other help methods) (mostly this is true already)

 - Python3 (works in release-1.x branch now, minus txsocksx)

 - Re-org docs, add "programming guide" (instead of walkthrough,
   tutorial and HOWTO)

 - consolidate examples (there's too many, and some are confusing)

 - introduce a "Tor" object that abstracts "a running tor instance"
   (whether launched by txtorcon or just connected-to) as a Builder
   or Factory for other useful objects. This would be "the" high-level
   API that most users would interact with. Something like:

       def main(reactor):
           tor = yield txtorcon.launch(reactor, ...)  # or .connect()
           torstate = yield tor.create_state()
           print("all circuits:", torstate.circuits.values())
           endpoint = tor.create_client_endpoint('torproject.org', 443)
           onion = tor.create_onion_endpoint(port=80, private_key=None)
           # etc.

   This would get rid of "launch_tor", "build_local_tor_connection" and
   others, giving just "launch()" or "connect()". get_global_tor() would
   also return a "Tor" instance. Also, launch() would *not* take an
   arbitrary TorConfig (as launch_tor does now) but instead would expose
   a very few critical options as kwargs (and if you need to mess around
   with obscure options, you'd do so after launch).

 - .get_info() should never have returned a dict (instead: list of
   results, in same order as keys)

 - consolidate all the various types of "onion/hidden-service" things to
   support ephemeral and "on disk" services, as well as
   authenticated. There are currently conceptually 6 variants from tor:

       ephemeral: plain, basic-auth (not in tor), stealth-auth (not in tor)
         on-disk: plain, basic-auth, stealth-auth

   This is further complicated by the fact that both the authenticated
   services are really, logically, a "list of clients" each of which has
   a name, a secret (and for stealth, a separate .onion address). My
   current design *ideas* are in the release-1.x branch, but boil down
   to interfaces: IOnionClients (for basic + stealth auth) which is a
   collection of IOnionClient instances (has secret + name, and is a
   subclass of IOnionService) and IOnionService for all the rest (has
   hostname, ports, private-key). This stuff is the most in-flux still.

   "create a new onion service" would be available at the high level via
   one or several method-calls on Tor() instances which would return new
   concrete IStreamClientEndpoint or IStreamServerEndpoint implementers

 - For "I want a Stream over Circuit X", add a ".stream_to(endpoint)"
   method on Circuit instances that gives you a Twisted
   IStreamClientEndpoint implementation causing the stream resulting
   from .connect() to be attached to that specific circuit.

 - Introduce a configurable "CircuitBuilder" to more-easily control
   construction of "types of" circuits (instead of just "build a circuit
   through these exact relays" as .build_circuit() provides). For more,
   see: https://github.com/meejah/txtorcon/issues/125

 - re-consider all the magic (attribute-style access) of TorConfig

 - Add a "composible"-style API for listening to Circuit and Stream
   events (instead of having to implement ICircuitListener etc).

I would be happy to hear of (other) existing APIs that are awkward or
confusing as well as opinions on the general colour of my
bikeshed. Please beware that this branch is very much "in progress" ;)

As far as current users of 0.x releases: I will not break these, and
will backport any critical fixes to them. My preference would be to
simply work with existing users (e.g. via pull-requests to your repos)
to let them seamlessly upgrade to 1.x as soon as 1.0.0 is pushed out the
door. Where possible I can provide wrappers for backwards-compatiblity
for any removed/re-named methods

My goal here is *not* to just gratuitously break things "because
aesthetics" but to make the "API surface" of txtorcon smaller, easier to
understand and better documented.

How to help:

 - look at http://txtorcon.readthedocs.org/en/release-1.x/ (note that
   some of the docs are lies as the code doesn't always exist yet, or
   worse yet exists but isn't what I want)

 - express opinions (here, #tor-dev, via any of the methods at

 - *maaaybe* look at the new code (but I'm trying to write the docs
   first, so those are the most-useful to look at). I want the docs to
   reflect the upcoming reality, and will change the code to match.


More information about the tor-dev mailing list