The maze book for programmers!

Algorithms, circle mazes, hex grids, masking, weaving, braiding, 3D and 4D grids, spheres, and more!

DRM-Free Ebook

The Buckblog

assorted ramblings by Jamis Buck

Refactoring Net::SSH: Part 7

21 November 2004 — 2-minute read

The Great Net::SSH Refactoring is nearing completion! I still need to add some unit tests for the KeyFactory class, but after that, it will be ready for a 0.5.0 release. One caveat—I’ll be releasing it without SFTP support.

Before anyone keels over from suspense, let me clarify that last remark. I am not abandoning SFTP support. Instead, I’m refactoring it out of the core Net::SSH deliverable, into it’s own library. It will (of course) depend on Net::SSH, but Net::SSH itself will no longer ship with SFTP support.

This isn’t as bad as it may seem, especially if you are using a package manager. If you are using a package manager, you’ll just go to install Net::SFTP, and voila, it will install Net::SSH as well (because that is a dependency).

This makes my life easier, since Net::SFTP was rapidly growing in complexity. It makes it easier to manage if it is its own library. It also means I can release the new version of Net::SSH sooner, since Net::SFTP is going to take about a week (or two) longer to refactor and repackage.

Besides that drastic side-effect of refactoring, I’ve also revisited how I did the transport, user-auth and connection layers. In particular, the transport session originally had to be explicitly opened after it was created. This was a side effect of when I had envisioned a single registry containing multiple Net::SSH connections—I’ve since abandoned that approach, and have required that a single registry contain no more than a single Net::SSH connection. (Well, if you’re clever you could still do multiple connections by managing namespaces right, but that would be more trouble than it’s worth.)

So, now that the transport session is a singleton, it made no sense to require the #open call to be made explicitly. Instead, now the various connection parameters and options are registered as services, and the session is opened automatically when the service is created.

This means that dependency injection can really shine, now. Consider the following scenario:

Net::SSH::Session is asked to open a new connection. It instantiates a registry and registers all the necessary services. Then, it grabs the user-auth service, to authenticate the user. This has a dependency on the transport session, so Needle instantiates the transport session first (which makes the connection, negotiates the algorithms to use, and so forth), and then instantiates the user-auth service. It then invokes the #authenticate method, gets the active connection service and returns.

I could have removed the explicit #authenticate call, as well, but I wanted to have more control over how a failed authentication is reported to the user. I suppose I could have registered some proc as a service, which when the authentication fails the proc gets called…but that’s complicating things unnecessarily.

I like the system much better now.

I’ll be releasing Net::SSH 0.5.0 next week, with any luck. Watch for it!