<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://mat.geeky.net/feed.xml" rel="self" type="application/atom+xml" /><link href="https://mat.geeky.net/" rel="alternate" type="text/html" /><updated>2025-12-10T22:04:26+00:00</updated><id>https://mat.geeky.net/feed.xml</id><title type="html">Mat Trudel</title><subtitle></subtitle><author><name>Mat Trudel</name></author><entry><title type="html">Bandit is all grown up</title><link href="https://mat.geeky.net/2023/10/19/bandit-is-all-grown-up.html" rel="alternate" type="text/html" title="Bandit is all grown up" /><published>2023-10-19T00:00:00+00:00</published><updated>2023-10-19T00:00:00+00:00</updated><id>https://mat.geeky.net/2023/10/19/bandit-is-all-grown-up</id><content type="html" xml:base="https://mat.geeky.net/2023/10/19/bandit-is-all-grown-up.html"><![CDATA[<p>BLUF: Bandit and Thousand Island go 1.0.0 today</p>

<p>I started writing <a href="https://github.com/mtrudel/bandit">Bandit</a> and <a href="https://github.com/mtrudel/thousand_island">Thousand
Island</a> almost <a href="https://github.com/mtrudel/bandit/tree/08e230161eeee29e48962c0342a358d1a7b00f41">four years
ago</a>
(!), initially as a bit of a joke. Despite its humble beginnings it quickly
became apparent to me that there was something to the project beyond humour, and
once things started getting a bit more serious with the project I broke down the
work to get to a 1.0 release, a journey which ended up looking something like
this:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">0.1.x</code> series: Proof of concept (along with Thousand Island) sufficient to support HAP. Nov 2019 to Nov 2020 (12 months)</li>
  <li><code class="language-plaintext highlighter-rouge">0.2.x</code> series: Revise process model to accommodate forthcoming HTTP/2 and WebSocket adapters. April-May 2021 (2 months)</li>
  <li><code class="language-plaintext highlighter-rouge">0.3.x</code> series: Implement HTTP/2 adapter. May-Sept 2021 (4 months)</li>
  <li><code class="language-plaintext highlighter-rouge">0.4.x</code> series: Re-implement HTTP/1.x adapter. Sept 2021 to April 2022 (7
months)</li>
  <li><code class="language-plaintext highlighter-rouge">0.5.x</code> series: Implement WebSocket extension &amp; Phoenix support. April-Nov 2022 (7 months)</li>
  <li><code class="language-plaintext highlighter-rouge">0.6.x</code> series: Comprehensive performance optimization &amp; telemetry coverage.
Nov 2022 to Mar 2023 (5 months)</li>
  <li><code class="language-plaintext highlighter-rouge">0.7.x</code> series: Enhance startup options, general quality-of-life issues.
Mar-Apr 2023 (2 months)</li>
  <li><code class="language-plaintext highlighter-rouge">1.0.0-pre.x</code> series: Ready for general use, without reservation. Apr 2023-today (5 months)</li>
</ul>

<p>All in all, I think my planning was pretty solid! There were a few
periods where I would put the project down for months at a time and a few
periods (mostly in the run-up to conference presentations!) where I would do
months worth of work in the span of a few weeks, but generally progress was
pretty steady (if a bit slower than I was expecting).</p>

<p>One mistake that I will note was that I called the <code class="language-plaintext highlighter-rouge">1.0.0-pre.x</code> series far too
early. In hindsight I ought to have run a <code class="language-plaintext highlighter-rouge">0.8.x</code> series to shake out any
lingering bugs before moving to a pre-release series, particularly because Hex
requires people to opt-in to get pre-release versions. As a result the testing pool
for the pre-release series wasn’t as large as it should have been.</p>

<p>Throughout it all I’ve been lucky enough to talk about Bandit &amp; Thousand
Island at a number of conferences (<a href="https://www.youtube.com/watch?v=ZLjWyanLHuk">ElixirConf
2021</a>, <a href="https://www.youtube.com/watch?v=FtZBTUvRt0g">EMPEX
MTN</a>, and <a href="https://www.youtube.com/watch?v=usKLrYl4zlY">ElixirConf EU
2023</a>) and have been a guest on
several podcasts to talk about my work on Bandit and networking in Elixir more
generally. It’s been a great trip, and has produced some of the best work I’ve
ever done. For anyone out there who’s pondering starting up their own project
that seems ambitious but attainable at the same time, 10/10 would recommend.
It’s a lot of fun.</p>

<p>After all of this, it seems a bit anti-climactic to say that Bandit and Thousand
Island are both going 1.0 later today. There’s still a lot more work to be done
(see below!) but none of that work needs to block a <code class="language-plaintext highlighter-rouge">1.0.0</code> release from
happening. So here we are, get ‘em while they’re hot:</p>

<div class="language-elixir highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="ss">:bandit</span><span class="p">,</span> <span class="s2">"~&gt; 1.0"</span><span class="p">},</span>
<span class="p">{</span><span class="ss">:thousand_island</span><span class="p">,</span> <span class="s2">"~&gt; 1.0"</span><span class="p">}</span>
</code></pre></div></div>

<p>I’d be in remiss if I didn’t call out all the folks who have helped out along
the way; over 20 different people have submitted PRs large and small to the
projects, and many more have filed thoughtful bugs that helped highlight some of
the corner cases in the underlying RFCs. In particular,
<a href="https://github.com/moogle19">moogle19</a>, <a href="https://github.com/ryanwinchester">Ryan
Winchester</a>, and <a href="https://github.com/alisinabh">Alisina
Bahadori</a> have been extremely helpful,
reviewing PRs &amp; helping to triage issues from the community. The project
wouldn’t be what it is today without their (and many others!) help. Thanks
everyone!</p>

<p>Looking to the future, we still have a bunch of stuff in the works:</p>

<ul>
  <li><a href="https://github.com/mtrudel/bandit/issues/91">Adding support</a> for WebSockets
over HTTP/2, as defined in <a href="https://www.rfc-editor.org/rfc/rfc8441">RFC8441</a>.
This requires a fairly extensive overhaul of the HTTP/2 process model, but
<em>should</em> be doable while maintaining backwards compatibility and so will be a
later <code class="language-plaintext highlighter-rouge">1.x</code> release</li>
  <li>Moving protocol switching into Thousand Island, to mirror the transport
upgrade work <a href="https://github.com/mtrudel/thousand_island/pull/86">currently in
progress</a></li>
  <li>Implementing NIF/Rustler based support for native implementations of hot code
paths within Bandit. This will be opt-in by default, but should provide for
some substantial performance gains in many common cases</li>
  <li>Implementing improvements to Plug (or elsewhere) to facilitate gRPC style
connections. This is likely a <code class="language-plaintext highlighter-rouge">2.0</code> feature</li>
  <li>HTTP/3 support remains on the horizon, though it’s still a long way away</li>
</ul>]]></content><author><name>Mat Trudel</name></author><summary type="html"><![CDATA[BLUF: Bandit and Thousand Island go 1.0.0 today]]></summary></entry><entry><title type="html">bandit on the loose</title><link href="https://mat.geeky.net/2021/06/24/bandit-on-the-loose.html" rel="alternate" type="text/html" title="bandit on the loose" /><published>2021-06-24T00:00:00+00:00</published><updated>2021-06-24T00:00:00+00:00</updated><id>https://mat.geeky.net/2021/06/24/bandit-on-the-loose</id><content type="html" xml:base="https://mat.geeky.net/2021/06/24/bandit-on-the-loose.html"><![CDATA[<p><a href="https://github.com/mtrudel/bandit">bandit</a> is the name of an HTTP server I’ve been writing over
the past several months. It is written entirely in Elixir and supports HTTP/1.x and HTTP/2 over
both secure and unsecure connections. As of version 0.3.2 (released today!), it should support
almost all HTTP client connections, although full HTTP/2 compliance is still a work in progress
(it currently scores 75% on the <a href="https://github.com/summerwind/h2spec">h2spec</a> suite, with plans
for 100% compliance by the end of the 0.3.x release train).</p>

<p>As I’ve <a href="/2021/06/16/Get-at-it-then.html">talked about before</a>, bandit was originally
created out of necessity to sit in between <a href="https://github.com/mtrudel/thousand_island">Thousand
Island</a> and <a href="https://github.com/mtrudel/hap">HAP</a>. The
0.1.x releases of bandit were very much works in progress, with little testing and rough edges
aplenty. It really only implemented the barest of requirements to satisfy the HTTP/1.1 needs of
the HomeKit Accessory Protocol, with Thousand Island providing the custom socket-level encryption
required. Now that HAP has more or less reached completion, I’m turning my attention back to
bandit to focus on its usefulness as a general purpose Plug-centric HTTP server.</p>

<h3 id="how-bandit-works">How bandit Works</h3>

<p>Like almost any server, bandit has a pretty straightforward job:</p>

<ol>
  <li>Wait for connections from clients</li>
  <li>Handle each connection to completion</li>
  <li>Do the above as efficiently as possible</li>
</ol>

<p>Fortunately for us, steps 1 and 3 are largely addressed by the underlying <a href="https://github.com/mtrudel/thousand_island">Thousand
Island</a> library. As a socket server, its job is to
listen for connections on a TCP port (with optional SSL/TLS security) and pass each separate
client connection to a <em>handler module</em> for processing. Thousand Island doesn’t concern itself
with what a handler module actually does with the connection; the handler could be an HTTP server
or any other protocol, custom or otherwise.  A socket server’s only job is to accept client
connections as they come in and to efficiently pass them up to whatever handler module is
configured.</p>

<p>I’ll have lots more to say about Thousand Island in a future post, but for now it’s sufficient to
understand that every client connection ends up as a distinct Elixir process; one TCP connection
equals one Elixir process. Each such process is handled in complete isolation from one another, so
a handler module implementation only needs to concern itself with how to handle a single
connection. A handler process is free to take as long as it needs to properly handle its single
connection, without regard for the overall (network) scalability of the server.</p>

<p>When it comes to implementing a handler module to actually handle an HTTP client connection and
see it through to completion, the particular details of HTTP as a protocol come into play. The
atomic unit of an HTTP connection is a <strong>request</strong>. If you’ve ever connected to an HTTP server via
<code class="language-plaintext highlighter-rouge">telnet</code> or <code class="language-plaintext highlighter-rouge">nc</code> you’ve likely seen something like the following:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ nc example.com 80
&gt; GET /hello_world HTTP/1.1
&gt;
&lt; HTTP/1.1 200 OK
&lt; Content-Length: 12
&lt; 
&lt; Hello, World
</code></pre></div></div>

<p>This is the simplest example of an HTTP/1.1 request from start to finish; a client connects, asks
to undertake a specific action on a specific resource (to <code class="language-plaintext highlighter-rouge">GET</code> the <code class="language-plaintext highlighter-rouge">/hello_world</code> resource in
this example), and the server responds with the result.</p>

<p>In the case of bandit and other <a href="https://github.com/elixir-plug/plug">Plug</a> based servers, the 
actual business logic of fulfilling a request is carried out by an application by means of the 
Plug API. Each client HTTP request is translated into a <code class="language-plaintext highlighter-rouge">Plug.Conn</code> struct and passed to the 
application via the <a href="https://hexdocs.pm/plug/Plug.html">Plug</a> behaviour. The Plug API provides
functionality to enable application code to render responses back to the client, which again is
mediated back to a server implementation via the Plug API (the
<a href="https://hexdocs.pm/plug/Plug.Conn.Adapter.html">Plug.Conn.Adapter</a> behaviour in this case). At 
its core, even a complex application framework such as Phoenix is ‘just’ a Plug application<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup>.</p>

<p>Putting all this together, we have a stack that looks something like this:</p>

<p><img src="/images/bandit-protocol-stack.png" alt="Protocol stack diagram" class="inline-image" /></p>

<p>The job of a Plug based HTTP server is to accept client connections and convert every request
within that connection into a Plug call. With HTTP/1.x clients such as the previous example, this
is fairly straightforward. HTTP/1.x connections can only make a single request at a time (and in
fact often only ever issue a single request before closing the connection). From a process
perspective things are simple; since Thousand Island provides us each connection in its own
process, and since only a single request can be in progress at a given time within that
connection, it is a natural fit to simply host the Plug call in the same process that Thousand
Island provides us. It’s a simple process model that completely captures the needs of the protocol
while also being scalable.</p>

<p>Supporting HTTP/2 is a bit trickier. The primary benefit of HTTP/2 over previous versions is that it
supports making multiple concurrent requests within a single connection (in HTTP/2, these separate
requests are called <em>streams</em>). At any given time, an HTTP/2 connection may have zero, one, or
hundreds of concurrent streams on the go, and the job of an HTTP server becomes much more
complicated as a result. Various failures and error conditions are local to the stream (in which
case other streams within the connection are unaffected), while some are fatal to the connection
as a whole. Moreover, since each stream contains its own request and each request maps directly
onto a Plug call, we need to devise a way to run each stream within its own process but still
be subservient to the overall connection process.</p>

<p>As it turns out, this isn’t actually all that difficult thanks to the wonders of OTP’s process
model. I’ll be covering the bandit HTTP/2 process model in detail in a future post, but the
implementation is actually pretty straightforward; we end up with a single process to manage the
overall connection (this is the same process that is handed to us by Thousand Island), as well as
one process per stream. The individual stream processes are essentially thin wrappers around
a Plug call, and exist mostly to allow streams to be processed concurrently. Meanwhile, the
connection process takes care of marshalling the stream processes, ensuring synchronization of
network communication, and managing the overall connection life cycle.</p>

<h3 id="current-status">Current Status</h3>

<p>As of 0.3.2 (released today), bandit should be usable for almost everything you can throw at it 
from common HTTP/1.x and HTTP/2 clients. There are a number of HTTP/2 features still to implement,
but most interactions should be able to hobble along in their absence. The general roadmap forward
is as follows:</p>

<ul>
  <li>Implement HTTP/2 support in the 0.3.x release train (targeting a Q321 completion)
    <ul>
      <li>Implement <a href="https://datatracker.ietf.org/doc/html/rfc7540#section-6.10">CONTINUATION</a> frame support in 0.3.3</li>
      <li>Implement <a href="https://datatracker.ietf.org/doc/html/rfc7540#section-6.9">WINDOW_UPDATE</a> and <a href="https://datatracker.ietf.org/doc/html/rfc7540#section-6.3">PRIORITY</a> frame support in 0.3.4</li>
      <li>Implement <a href="https://datatracker.ietf.org/doc/html/rfc7540#section-6.6">PUSH_PROMISE</a> frame support in 0.3.5</li>
      <li>Improve <a href="https://datatracker.ietf.org/doc/html/rfc7540#section-6.5.2">SETTINGS</a> compliance in 0.3.6</li>
      <li>Tackle any remaining h2spec conformance issues in 0.3.7</li>
    </ul>
  </li>
  <li>Re-implement HTTP/1.x support in the 0.4.x release train (the current implementation is somewhat
patchwork as it dates from my earliest 0.1.x work)</li>
  <li>Add WebSocket support in the 0.5.x release train (details TBD)</li>
  <li>Improve overall documentation, configurability &amp; telemetry support in the 0.6.x release train</li>
  <li>Integrate with Phoenix’s adhoc Cowboy support in the 0.7.x release train</li>
  <li>Roughly targeting Q122 for a bandit / Thousand Island 1.0 release</li>
</ul>

<p>A primary goal of bandit is strict protocol conformance. Throughout the 0.3.x release train,
I have been making extensive use of the <a href="https://github.com/summerwind/h2spec">h2spec</a> test suite,
and have wired it up into the <a href="https://github.com/mtrudel/bandit/blob/master/test/bandit/http2/h2spec_test.exs">bandit test
suite</a>.
This is actually a pretty neat little bit of test tooling (due credit to Ace’s <a href="https://github.com/CrowdHailer/Ace/blob/master/test/ace/http2/h2spec_test.exs">h2spec
test</a> which was the
inspiration for this). This setup makes it possible for me to develop features while testing
directly against an external conformance suite, even narrowing the tests down to a particular
section of the HTTP/2 spec:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Let's test some stream state transitions...</span>
<span class="nv">$ H2SPEC</span><span class="o">=</span>http2/5.1 mix test.watch <span class="nt">--only</span> external_conformance
</code></pre></div></div>

<p>These tests are in addition to exhaustive protocol and Plug API conformance testing, both done
using more conventional ExUnit testing. The combination is proving to be both comprehensive and
efficient, and I’m hoping to set something similar up for the upcoming HTTP/1.x and WebSockets
work.</p>

<h3 id="wrapping-it-up">Wrapping It Up</h3>

<p>Over the next several months I’ll have lots more to say about bandit, Thousand Island, and HAP.
I’m planning on doing a series of long-form articles diving into the details of each library and
also some shorter pieces covering current development progress along the way towards 1.0 releases
of bandit and Thousand Island. Please check out the <a href="https://github.com/mtrudel/thousand_island">Thousand
Island</a> and
<a href="https://github.com/mtrudel/bandit">bandit</a> projects, kick the tires on them and let me know what
you think (and of course, PRs are always welcome!)</p>
<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p>In truth, Phoenix is tied a bit more strongly to the Cowboy HTTP server than it should be, mostly due to the lack of a Plug-like behaviour to abstract WebSocket connections. Refactoring this interface so that Phoenix can work just as well on bandit (or any other compliant HTTP server) is a primary goal of the bandit project. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>Mat Trudel</name></author><summary type="html"><![CDATA[bandit is the name of an HTTP server I’ve been writing over the past several months. It is written entirely in Elixir and supports HTTP/1.x and HTTP/2 over both secure and unsecure connections. As of version 0.3.2 (released today!), it should support almost all HTTP client connections, although full HTTP/2 compliance is still a work in progress (it currently scores 75% on the h2spec suite, with plans for 100% compliance by the end of the 0.3.x release train).]]></summary></entry><entry><title type="html">Get at it, then</title><link href="https://mat.geeky.net/2021/06/16/Get-at-it-then.html" rel="alternate" type="text/html" title="Get at it, then" /><published>2021-06-16T00:00:00+00:00</published><updated>2021-06-16T00:00:00+00:00</updated><id>https://mat.geeky.net/2021/06/16/Get-at-it-then</id><content type="html" xml:base="https://mat.geeky.net/2021/06/16/Get-at-it-then.html"><![CDATA[<p>About eighteen months ago I got the idea in my head that we should be able to control our house
air conditioner via HomeKit. Like most of its ductless brethren our air conditioner is
controlled exclusively via IR; my plan was to use <a href="http://nerves-project.org">Nerves</a> on
a Raspberry Pi to create an IR blaster of sorts that could be controlled via HomeKit. A quick
search confirmed that there were no existing HomeKit libraries for Elixir but this seemed like
more of an invitation than a problem; the <a href="https://developer.apple.com/homekit/specification/">HomeKit Accessory
Protocol</a> is a publicly available
specification and there are numerous existing libraries such as
<a href="https://homebridge.io">Homebridge</a> that work with it, so how hard could it be?</p>

<p>The answer, as it turns out, is ‘rather’.</p>

<p>I’ve mostly reached the end of this project (or at least, I’m far enough into it to have
a complete map of everything that needs to be done to get it over the line), and along the way
I’ve had to take quite a few detours:</p>

<ul>
  <li>I built a Nerves powered <a href="https://github.com/mtrudel/desk_clock">desk clock</a> to learn the ins
and outs of Nerves (<a href="https://github.com/mtrudel/talks/blob/master/2020-07-Toronto-Elixir-Night-Nerves.pdf">I did a talk about
it</a>).
There were a few sub-detours here as well to <a href="https://github.com/mtrudel/ex_paint">draw things</a>
and also to <a href="https://github.com/mtrudel/ssd1322">display them</a></li>
  <li>I wrote <a href="https://github.com/mtrudel/thousand_island">Thousand Island</a>, a pure-Elixir socket server
(along the lines of <a href="https://github.com/ninenines/ranch">ranch</a>) to power the socket-level
encryption required by the HomeKit Accessory Protocol (I <a href="https://github.com/mtrudel/talks/blob/master/2020-01-Toronto-Elixir-Night-Thousand-Island.pdf">did a talk about this
too</a>)</li>
  <li>I wrote a pure-Elixir HTTP server called <a href="https://github.com/mtrudel/bandit">bandit</a> to work 
alongside Thousand Island</li>
  <li>I implemented the HomeKit Accessory Protocol in Elixir and released it as <a href="https://github.com/mtrudel/hap">HAP</a>.
It allows Elixir apps to act as HomeKit accessories &amp; be natively controlled from any iOS device
(HomeKit support is built into iOS)</li>
  <li>Along the way I submitted a half-dozen or so upstream issues, ranging from <a href="https://github.com/SiliconJungles/eqrcode/pull/11">QR code
rendering</a> to a subtle but nasty <a href="https://bugs.erlang.org/browse/ERL-1078">crypto bug in
OTP</a></li>
</ul>

<p>I’m a big fan of the <a href="https://twitter.com/kentbeck/status/250733358307500032">make hard changes
easy</a> philosophy, and so while the list of
diversions I’ve taken along the way may seem long, it was really just a matter of iteratively
breaking the large problem down into a series of small ones &amp; working them through. And
now—finally!—I’m at the point where I can write a simple Nerves app that uses HAP to
talk to HomeKit &amp; interfaces with an IR blaster to actually control our air conditioner (I haven’t
<em>quite</em> figured out that last bit yet, but it’s a solvable problem &amp; just needs to be done).</p>

<p>In the spirit of <a href="http://carl.flax.ie/dothingstellpeople.html">do things, tell people</a> I’ll be
laying out a series of posts here over the next several months describing this journey &amp; the
things I’ve built along the way, as well as the parts I still have to build. While I think there’s
a lot of value in HAP on its own, I’ve come to believe that Thousand Island and bandit are
probably the real crown jewels of this whole project and I’m excited to share them with people.</p>

<p>The Elixir web stack is developing at a breakneck speed, with
<a href="https://www.phoenixframework.org">Phoenix</a> pioneering a bunch of features that are miles beyond
most other platforms. However, the layers further down the Elixir networking stack start to become
quite opaque quite quickly. <a href="https://github.com/ninenines/cowboy">Cowboy</a> and
<a href="https://github.com/ninenines/ranch">ranch</a> are both fantastic libraries, but they can be quite
daunting reads for an Elixir developer unfamiliar with Erlang, even more so as they do quite a bit
more than serve requests to a Plug API. As a result the lower levels of the Elixir network stack
aren’t as discoverable as they should be, which is a particular shame as this is one of the places
where the unique genius of OTP really shines.</p>

<p><a href="https://github.com/mtrudel/thousand_island">Thousand Island</a> and
<a href="https://github.com/mtrudel/bandit">bandit</a> are key missing pieces to help bridge this gap.
Between them, they provide some very tangible benefits to the Elixir community:</p>

<ul>
  <li>
    <p>Thousand Island provides straightforward &amp; extremely flexible APIs entirely in native Elixir,
making it easy for any Elixir developer to build their own network services using a familiar 
set of tooling. Applications get essentially unlimited network scaling for free, based on
Thousand Island’s use of standard OTP design principles. Comprehensive
<a href="https://github.com/beam-telemetry/telemetry">telemetry</a> instrumentation provides built-in
visibility all the way down to the socket level</p>
  </li>
  <li>
    <p>bandit provides a modern web server with robust &amp; extensively conformance tested implementations
of foundational standards such as <a href="https://datatracker.ietf.org/doc/html/rfc2616">RFC 2616</a>
(HTTP/1.1), <a href="https://datatracker.ietf.org/doc/html/rfc7540">RFC 7540</a> (HTTP/2), and <a href="https://datatracker.ietf.org/doc/html/rfc6455">RFC
6455</a> (WebSockets) and is built specifically to
serve a Plug API. Less complexity &amp; modern idioms make bandit the obvious choice for future
development on emerging standards such as <a href="https://datatracker.ietf.org/doc/html/rfc9000">QUIC</a></p>
  </li>
  <li>
    <p>Both libraries have been built from day one to be approachable, clean in design, and easy to
understand and extend. They both deeply embrace OTP design principles and serve as great case
studies for what the platform is capable of</p>
  </li>
  <li>
    <p>By providing a second implementation of a supporting HTTP server, bandit will help to improve the 
robustness and flexibility of the Plug and low-level Phoenix APIs to ensure that they are truly
agnostic to the underlying library &amp; can grow to adopt currently unsupported features such as
HTTP trailers</p>
  </li>
</ul>

<p>All-in-all, I’m <strong>very</strong> excited to see where the rest of this journey takes this project.  While
it’s still early days, I don’t think it’s too audacious of a goal to see Thousand Island &amp; bandit
take the lead as the go-to libraries for networking in Elixir, or even to see them as the default
choice in new Phoenix installs sometime in the future. Stay tuned!</p>]]></content><author><name>Mat Trudel</name></author><summary type="html"><![CDATA[About eighteen months ago I got the idea in my head that we should be able to control our house air conditioner via HomeKit. Like most of its ductless brethren our air conditioner is controlled exclusively via IR; my plan was to use Nerves on a Raspberry Pi to create an IR blaster of sorts that could be controlled via HomeKit. A quick search confirmed that there were no existing HomeKit libraries for Elixir but this seemed like more of an invitation than a problem; the HomeKit Accessory Protocol is a publicly available specification and there are numerous existing libraries such as Homebridge that work with it, so how hard could it be?]]></summary></entry><entry><title type="html">2012 in review</title><link href="https://mat.geeky.net/2012/12/29/2012-in-review.html" rel="alternate" type="text/html" title="2012 in review" /><published>2012-12-29T00:00:00+00:00</published><updated>2012-12-29T00:00:00+00:00</updated><id>https://mat.geeky.net/2012/12/29/2012-in-review</id><content type="html" xml:base="https://mat.geeky.net/2012/12/29/2012-in-review.html"><![CDATA[<p><a href="http://rapgenius.com/Mos-def-fear-not-of-man-lyrics#lyric">21st century is comin, 20th century almost done</a> (thirteen years too late, but it’s a solid song. You simply can’t go wrong with Fela Kuti). In the spirit of <a href="http://nathanbarry.com/2012-year-quitting-job/">everyone</a> <a href="http://www.kalzumeus.com/2012/12/29/bingo-card-creator-and-other-stuff-year-in-review-2012/">else</a> talking about their years, I’m jumping on that wagon too. Here goes.</p>

<h2 id="setting-the-scene">Setting the scene</h2>

<p>From January through May, we were living in Waterloo with my in-laws. We moved back to our house in Toronto in May, and spent August in Italy. That gives us about six months of ‘normalcy’. Taking into account the work I started while living in Waterloo, I’m counting roughly 7 months of work done in 2012. Now that our family’s health issues are (hopefully) behind us, I’m expecting 2013 to be a full year work-wise (which means roughly 10½ months of paying work planned for 2013).</p>

<h2 id="what-went-well">What went well</h2>

<p>I’ve had three large contracts throughout the year, plus a few smaller one-off engagements. At a high level, I’m really enjoying contracting. Although I remember my time as a wage-slave with nostalgia, I prefer the freedom (both time and technical) that contracting affords. So that’s good.</p>

<p>I spent about 40% of my time in 2012 on iOS development, and having developed 8 apps from conception to ship-ready, I now consider it my most solid platform. Sharecropping issues aside, I really enjoy writing in it, am very productive, and have enough contacts for future contracts that I can keep busy (and command a good rate) for the foreseeable future. In that sense, my iOS work has been a good short-to-medium term investment. I’m wary of basing a long-term career on it, but for now it’s too lucrative (and frankly too enjoyable) to pass up.</p>

<p>The same goes (to a lesser extent) with Javascript, where I also spent about 40% of my time. I’ve now done enough work that I have my own style (and reasons for it, and am perfectly comfortable with the idioms and limitations of the language. I don’t really like it all that much, but it’s an undeniable fact of life, and with my long term goal of moving towards the open world, I can’t ignore it.</p>

<p>Money wise, we’re well ahead of our monthly burn rate, with lots of money left over (if anyone is interested, I’m happy to talk harder numbers, just not in public). All my contracts are reliable clients, so collecting hasn’t been an issue (with the caveat that waiting to get paid for the first few months of contracting was really tough). So overall we’re good on the money front.</p>

<p>2012 was also the first time that I’ve ever bothered doing any formal paperwork in terms of running a business (for now that means registering as a sole proprietor &amp; getting an HST number. I’ll look at incorporating next year). While Freshbooks isn’t perfect, it’s 90% of what I need, and it’s free. Tax prep doesn’t look that much harder than previous years, and most of the financial decisions to be made with respect to incorporating / taxation / etc are quite clear to me. Contract negotiation and client management isn’t that hard either. In short, the actual running of a business is nowhere near as daunting as I’d always thought it to be. It’s actually kinda fun as long as I’m not doing it every day.</p>

<p>I also kicked out a couple of fun side projects this year, notably <a href="https://github.com/mtrudel/matchat">matchat</a>, <a href="https://github.com/mtrudel/easel">Easel</a>, and two yet-to-be-released iOS pods. One thing I really missed about working at Well.ca was the amount of fun &amp; short duration side projects I worked on. I’d like to design my work around more of those in 2013.</p>

<p>Near the end of the year I started doing weekly Skype checkins with an old <a href="http://www.dogpatchtech.com/">friend and colleague</a> with the aim of having a technical sounding board for tactical decisions, mostly technical in nature. This is helping a lot, especially with iOS development where I’m the only one of my Toronto cohort who’s on the platform. I’d like to keep doing more of this in 2013.</p>

<h2 id="what-went-badly">What went badly</h2>

<p>While we were still living in Waterloo (and while I was waiting for the paperwork to be processed on the first contract I picked up), I spent about two months putting three iPhone apps together. All of these apps are basically store-ready at this point, yet only one of them is actually in the store. Even though none of these apps are real money-makers, there’s still a psychological price to be paid for not shipping, especially with products that are this close to being done. I need to get better at this.</p>

<p>Networking. I did some in 2012, but not as much as I’d like. I’d set some goals in this respect with a few colleagues, and we all did a collectively awful job in living up to them. I’d like to do a better job of this in 2013.</p>

<p>Tuning out on vacation. We spent August in Italy, and I made some promises regarding workload during that time that I wasn’t able to keep. I let people down and created needless stress for myself when the better approach would have been to just unplug for the month. Next year, I’ll do that.</p>

<p>Other than that, I think 2012 was a banner year (at least considering where we stood this time last year), and there’s not a whole lot I would have changed.</p>

<p>Looking forward to 2013, I have contract work lined up through the first 4-6 months of 2013, with solid leads on work for the balance of the year. I’d like to wind down from 5 days a week to 3-4 by mid-summer, and take the balance of the time to tackle my own non-paying work. Either way, it’s comforting to know that the work is there if I need it. We’re also planning on taking a month off to travel again, probably in September.</p>

<p>So that’s that. As we wrap up 2012, taking stock of everything has reinforced what I already kind of knew; that it’s been quite a good year. And you?</p>]]></content><author><name>Mat Trudel</name></author><summary type="html"><![CDATA[21st century is comin, 20th century almost done (thirteen years too late, but it’s a solid song. You simply can’t go wrong with Fela Kuti). In the spirit of everyone else talking about their years, I’m jumping on that wagon too. Here goes.]]></summary></entry><entry><title type="html">Smart Keywords are Smart</title><link href="https://mat.geeky.net/2011/08/07/Introducing-Smart-Keywords.html" rel="alternate" type="text/html" title="Smart Keywords are Smart" /><published>2011-08-07T00:00:00+00:00</published><updated>2011-08-07T00:00:00+00:00</updated><id>https://mat.geeky.net/2011/08/07/Introducing-Smart-Keywords</id><content type="html" xml:base="https://mat.geeky.net/2011/08/07/Introducing-Smart-Keywords.html"><![CDATA[<p>Safari is a great browser, but has always had one feature missing that’s present in every other modern browser: <a href="http://support.mozilla.com/en-US/kb/Smart%20keywords">Smart Keywords</a>. Previously I’ve used tools such as <a href="http://www.kitzkikz.com/Sogudi">Sogudi</a> or <a href="http://alexstaubo.github.com/keywurl/">Keywurl</a> to provide that functionality within Safari, but they were both implemented via a fragile (if awesome) <a href="http://www.culater.net/software/SIMBL/SIMBL.php">hack</a>, and as a consequence I always pointed fingers at them whenever Safari started losing its shit in the past. Happily, with the arrival of Safari 5.1, Apple has added the requisite <a href="http://developer.apple.com/technologies/safari/whats-new.html">event hooks</a> to the extension API to enable Smart Keyword functionality as a first class extension citizen.</p>

<p><a href="https://github.com/mtrudel/Smart-Keywords">Smart Keywords</a> is my implementation of Smart Keywords for Safari, using these new APIs. It’s super simple (28 lines of Javascript, the majority of which is code to read &amp; write configuration data), easily configurable, and – owing to its simplicity – should be crashproof.</p>

<p>To install Smart Keywords, download the <a href="https://github.com/downloads/mtrudel/Smart-Keywords/SmartKeywords.safariextz">extension</a> and double click on it to install. Configuration is straightforward, and is done in the extension tab of Safari’s preferences. Due to the way in which extension configurations are defined, you can define a maximum of ten keywords (this is a soft limit. If you want more, either ask me, or else <a href="https://github.com/mtrudel/Smart-Keywords/">fork the project</a> and add them yourself).</p>

<p>To customize a keyword, enter in the keyword you want to match (say, for example ‘wiki’ to match searches of the form ‘wiki bananarama’). When you enter this keyword in the address bar, it will be replaced with the contents of the matching URL instead, with the remainder of your query being substituted in for <code class="language-plaintext highlighter-rouge">%s</code> in the URL. As an example, if you have the keyword ‘foo’ defined with a URL of <code class="language-plaintext highlighter-rouge">http://example.com/search?query=%s</code>, then entering ‘foo bananarama’ will take you to the URL <code class="language-plaintext highlighter-rouge">http://example.com/search?query=bananarama</code>. Note that spaces in your entered URL are automatically URL escaped to <code class="language-plaintext highlighter-rouge">%20</code>, which is usually what you want.</p>

<p>Comments / feedback are welcome. If you find any bugs or missing features, please <a href="https://github.com/mtrudel/Smart-Keywords/issues">let me know</a>!</p>]]></content><author><name>Mat Trudel</name></author><summary type="html"><![CDATA[Safari is a great browser, but has always had one feature missing that’s present in every other modern browser: Smart Keywords. Previously I’ve used tools such as Sogudi or Keywurl to provide that functionality within Safari, but they were both implemented via a fragile (if awesome) hack, and as a consequence I always pointed fingers at them whenever Safari started losing its shit in the past. Happily, with the arrival of Safari 5.1, Apple has added the requisite event hooks to the extension API to enable Smart Keyword functionality as a first class extension citizen.]]></summary></entry><entry><title type="html">This is how we do it</title><link href="https://mat.geeky.net/2011/02/05/Montell-Jordan-Has-Nuthin-On-Me.html" rel="alternate" type="text/html" title="This is how we do it" /><published>2011-02-05T00:00:00+00:00</published><updated>2011-02-05T00:00:00+00:00</updated><id>https://mat.geeky.net/2011/02/05/Montell-Jordan-Has-Nuthin-On-Me</id><content type="html" xml:base="https://mat.geeky.net/2011/02/05/Montell-Jordan-Has-Nuthin-On-Me.html"><![CDATA[<p>As <a href="http://news.ycombinator.com/item?id=2183540">promised</a>, a howto on setting up SSH agent forwarding, and the proper use of proxy commands to punch through bastion (aka gateway) hosts.</p>

<h2 id="agent-forwarding">Agent Forwarding</h2>

<p>The theory is described <a href="http://unixwiz.net/techtips/ssh-agent-forwarding.html">here</a>, but here’s a distilled version of how to get SSH Agent forwarding working:</p>

<ol>
  <li>
    <p>If you don’t already have one, create your SSH key pair via:</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ssh-keygen -t rsa
</code></pre></div>    </div>

    <p>Ensure that you put a passphrase on this (it can be as strong as you want, since you’ll only ever have to type it in once).</p>
  </li>
  <li>
    <p>Push the public key component to the remote server you want to connect to:</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> cat ~/.ssh/id_rsa.pub | ssh user@remote "cat &gt;&gt; .ssh/authorized_keys"
</code></pre></div>    </div>

    <p>Many OS’s (not OS X, sadly) include an <code class="language-plaintext highlighter-rouge">ssh-copy-id user@remote</code> command that automates this.</p>
  </li>
  <li>
    <p>Connect to the remote machine using your new key:</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh user@remote
</code></pre></div>    </div>

    <p>If you’re on OS X or a reasonably friendly Linux box, you should get a native OS dialog asking you for the passphrase you just put on your private key. Enter it, and you should be golden. If you’re on another OS that doesn’t provide an automated agent, you probably want to look at <a href="http://help.github.com/working-with-key-passphrases/">this</a> for more info.</p>
  </li>
  <li>
    <p>Note that you can now make onward connections from the remote machine without being prompted to authenticate again. Magic!</p>
  </li>
</ol>

<h2 id="proxying-connections-through-a-bastion-host">Proxying connections through a bastion host</h2>

<p>This is crazy useful for maintaining a cluster of machines without having to expose their SSH servers to the internet. All you need to keep open is ssh on your bastion host and you have access to anything on the internal machines nearly automatically. Here goes:</p>

<p>Let’s say you have an internal network of machines in a <code class="language-plaintext highlighter-rouge">.internal</code> domain (<code class="language-plaintext highlighter-rouge">maebe.internal</code>, <code class="language-plaintext highlighter-rouge">gob.internal</code>, etc). Assuming you already have SSH access to these machines as detailed in the previous section, you can simply add something like this to your <code class="language-plaintext highlighter-rouge">~/.ssh/config</code> file:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Host *.internal
ProxyCommand ssh &lt;bastion_host&gt; nc %h %p
</code></pre></div></div>

<p>and you’ll magically be able to run ssh commands like the following:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh maebe.internal
</code></pre></div></div>

<p>What??? How does my machine know to resolve maebe.internal from anywhere on the internet, you ask? What’s happening here is that SSH is applying the config for *.internal to your connection request, and running the request through <code class="language-plaintext highlighter-rouge">ProxyCommand</code>. As such, your destination hostname actually gets looked up in the DNS context of the bastion host, which (presumably) knows how to resolve maebe.internal. Once again, Magic!</p>]]></content><author><name>Mat Trudel</name></author><summary type="html"><![CDATA[As promised, a howto on setting up SSH agent forwarding, and the proper use of proxy commands to punch through bastion (aka gateway) hosts.]]></summary></entry><entry><title type="html">One of these things is not like the other</title><link href="https://mat.geeky.net/2011/01/07/One-of-these-things-is-not-like-the-other.html" rel="alternate" type="text/html" title="One of these things is not like the other" /><published>2011-01-07T00:00:00+00:00</published><updated>2011-01-07T00:00:00+00:00</updated><id>https://mat.geeky.net/2011/01/07/One-of-these-things-is-not-like-the-other</id><content type="html" xml:base="https://mat.geeky.net/2011/01/07/One-of-these-things-is-not-like-the-other.html"><![CDATA[<p>As a follow-on to Gruber <a href="http://daringfireball.net/linked/2011/01/07/pixelmator">today</a>, there’s <a href="http://most-advantageous.com/optimal-layout/">at least one program out there</a> whose outside-the-walled-garden version has features which the App Store version does not. Quoted from Optimal Layout’s product page:</p>

<blockquote>
  <p>Optimal Layout fully supports Spaces: you can easily see which Space a windows is in. In the version purchased from this site you can also move groups of windows between Spaces with a keyboard command, note that this feature is not available in the version of Optimal Layout available on Apple’s Mac App Store.</p>
</blockquote>

<p>As an <a href="http://bantapp.com">iOS App Store developer</a> I wish I could say I was more excited about the Mac App Store, but balkanization such as this can’t possibly bode well for the platform’s health outside the walled garden.</p>]]></content><author><name>Mat Trudel</name></author><summary type="html"><![CDATA[As a follow-on to Gruber today, there’s at least one program out there whose outside-the-walled-garden version has features which the App Store version does not. Quoted from Optimal Layout’s product page:]]></summary></entry><entry><title type="html">TIL</title><link href="https://mat.geeky.net/2010/12/13/TIL.html" rel="alternate" type="text/html" title="TIL" /><published>2010-12-13T00:00:00+00:00</published><updated>2010-12-13T00:00:00+00:00</updated><id>https://mat.geeky.net/2010/12/13/TIL</id><content type="html" xml:base="https://mat.geeky.net/2010/12/13/TIL.html"><![CDATA[<p><a href="http://www.newyorker.com/reporting/2010/12/20/101220fa_fact_paumgarten">Until this moment</a>, it had never occurred to me that Donkey Kong was indeed <strong>Donkey</strong> Kong. I’d honestly never actually seen the word donkey there, instead always assuming it was just a random jibberish name given to the bad guy.</p>

<p>Oops.</p>]]></content><author><name>Mat Trudel</name></author><summary type="html"><![CDATA[Until this moment, it had never occurred to me that Donkey Kong was indeed Donkey Kong. I’d honestly never actually seen the word donkey there, instead always assuming it was just a random jibberish name given to the bad guy.]]></summary></entry><entry><title type="html">You may find yourself in another part of the world</title><link href="https://mat.geeky.net/2010/11/22/You-may-find-yourself-in-another-part-of-the-world.html" rel="alternate" type="text/html" title="You may find yourself in another part of the world" /><published>2010-11-22T00:00:00+00:00</published><updated>2010-11-22T00:00:00+00:00</updated><id>https://mat.geeky.net/2010/11/22/You-may-find-yourself-in-another-part-of-the-world</id><content type="html" xml:base="https://mat.geeky.net/2010/11/22/You-may-find-yourself-in-another-part-of-the-world.html"><![CDATA[<p>On a dare from <a href="http://www.nmr.mgh.harvard.edu/~tisdall/">Dylan</a>, I wrote this up last night as a quick and dirty way of keeping track of where I left off in a given terminal window. When you’re walking away from a task, simply run</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>whereami &lt;note to self&gt;
</code></pre></div></div>

<p>and it will start being reflected in your terminal prompt. When you sit down to work again, run</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>whereami
</code></pre></div></div>

<p>with no arguments to clean out the note to yourself. Because it works using environment variables, you can use this on any number of terminal windows without interference.</p>

<p>Code here:</p>

<script src="https://gist.github.com/712063.js?file=gistfile1.sh"></script>

<p>This has also been added to my <a href="https://github.com/mtrudel/dotfiles/commit/fe507ea7">dotfile project</a>.</p>]]></content><author><name>Mat Trudel</name></author><summary type="html"><![CDATA[On a dare from Dylan, I wrote this up last night as a quick and dirty way of keeping track of where I left off in a given terminal window. When you’re walking away from a task, simply run]]></summary></entry><entry><title type="html">Hello filewall</title><link href="https://mat.geeky.net/2010/07/13/hello-filewall.html" rel="alternate" type="text/html" title="Hello filewall" /><published>2010-07-13T00:00:00+00:00</published><updated>2010-07-13T00:00:00+00:00</updated><id>https://mat.geeky.net/2010/07/13/hello-filewall</id><content type="html" xml:base="https://mat.geeky.net/2010/07/13/hello-filewall.html"><![CDATA[<p>I’m sick of firewalls. I’m sick of how arcane and arbitrary their config systems are. I’m sick of the fact that they’re never really reproducible, and that only one guy in most organizations understands their network (mostly because that guy was usually me).</p>

<p>On the other hand, I’ve always liked <a href="http://shorewall.net">shorewall</a>. Its config language has always seemed very flexible and easy to grok, it has great documentation, and since it’s just iptables under the covers, there’s no magic to it. Thinking about things further, I realized that most of my pain points were really more about how people go about setting up firewalls than about firewalls themselves. Such a central and yet seldom-touched piece of infrastructure is exactly the kind of place you want repeatability and process, and exactly the wrong place for ad-hoc hacks. Hence, <a href="http://github.com/well/filewall/">filewall</a> was born.</p>

<p>In one line, <strong>git + capistrano + shorewall = filewall</strong></p>

<p>Filewall is a mix of capistrano and shorewall that lets you keep your firewall configuration in SCM, and lets you deploy it to your routers in a simple, sane and structured way. It takes a great firewall and marries it to a great deployment system to make a great deployable firewall. Wicked.</p>

<p>Changes made with filewall are safely deployable; deployments incorporate a dead-man switch, wherein the rule changes are temporarily turned up for a timeout duration, and actually made permanent only if you subsequently affirm that they do what you intended them to. If you accidentally fry your config, filewall will restore your old configuration as soon as the timeout expires. You’ll never be locked out again.</p>

<p>Committed configurations are immediately wired into the filesystem, so your firewall works predictably across reboots. And since it’s <a href="http://capify.org">capistrano</a> based, you have access to all the rollback awesomeness that capistrano provides.</p>

<p>If you’re responsible for a more complex network, you can easily store all of your configurations as branches and keep all of your sensitive network config in one place, keeping all of your routers locked up with one public key. And don’t forget that software routers are <a href="http://freedomhec.pbworks.com/f/linux_ip_routers.pdf">fast</a>, so you probably won’t be outgrowing filewall anytime soon (and even if you do, filewall is hardware agnostic. As long as it runs Debian, it runs filewall).</p>

<p>So say hi to <a href="http://github.com/well/filewall/">filewall</a>. It’s what you want.</p>]]></content><author><name>Mat Trudel</name></author><summary type="html"><![CDATA[I’m sick of firewalls. I’m sick of how arcane and arbitrary their config systems are. I’m sick of the fact that they’re never really reproducible, and that only one guy in most organizations understands their network (mostly because that guy was usually me).]]></summary></entry></feed>