fasterthanli.meamos likes to tinkerhttps://fasterthanli.me/2024-11-23T17:40:00ZAmos Wengerhttps://fasterthanli.metoldhttps://cdn.fasterthanli.me/content/img/logo-square-2~12319eaafaaf55d3.pngHighlighted code in slideshttps://fasterthanli.me/articles/highlighted-code-in-slides2024-11-23T17:40:00Z<p data-bo="223">I have obsessed about this long enough, I think it's only fair I (and you!) get some content out of it.</p>
<p data-bo="328">When I started writing this article, I was working on my <a href="https://p99conf.io">P99 CONF</a> slides.
Those slides happen to include some bits of code. And because I'm a perfectionist, I would like this
code to be syntax highlighted, like this:</p>
<code class="code-block has-language-tag" translate="no" data-lang="rust""><label class="language-tag" title="Rust"></label><pre class="scroll-wrapper"><i class=hh4>let</i> addr<i class=hh9>:</i> <i class=hh13>SocketAddr</i> = config<i class=hh9>.</i><i class=hh6>address</i><i class=hh9>.</i><i class=hh3>parse</i><i class=hh8>(</i><i class=hh8>)</i>?<i class=hh9>;</i>
<i class=hh4>let</i> ln = <i class=hh13>TcpListener</i><i class=hh9>::</i>addr?
configbase_url
</pre></code>
<!-- playwall -->
ktls now under the rustls orghttps://fasterthanli.me/articles/ktls-now-under-rustls-org2024-09-26T21:10:00Z<a id="what-s-a-ktls" href="#what-s-a-ktls" class="anchor"><h2>What's a ktls</h2></a>
<p data-bo="151">I started work on <a href="https://crates.io/crates/ktls">ktls</a> and <a href="https://crates.io/crates/ktls-sys">ktls-sys</a>,
a pair of crates exposing <a href="https://www.kernel.org/doc/html/latest/networking/tls-offload.html">Kernel TLS offload</a>
to Rust, about <a href="https://github.com/rustls/ktls/commit/798466d7c3e659ecdf035afac0bea2b679aea4c4">two years ago</a>.</p>
<p data-bo="486">kTLS lets the kernel (and, in turn, any network interface that supports it) take care of encryption, framing,
etc., for the entire duration of a TLS connection... as soon as you <em>have</em> a TLS connection.</p>
<p data-bo="690">For the handshake itself (hellos, change cipher, encrypted extensions,
certificate verification, etc.), you still have to use a userland TLS
implementation.</p>
State of the fasterthanlime 2024https://fasterthanli.me/articles/state-of-the-fasterthanlime-20242024-08-07T07:14:05Z<p data-bo="133">It's time for some personal <em>and</em> professional news!</p>
<p data-bo="187">TL;DR: I started <a href="https://sdr-podcast.com">a podcast</a> with <a href="https://jamesmunns.com/contact/">James</a>,
I'm stable on antidepressants, I'm giving a <a href="https://www.p99conf.io/">P99 CONF</a> about my <a href="https://github.com/bearcove/fluke">Rust/io_uring/HTTP work</a>,
I'm trying on "they/them" as pronouns, I'm open-sourcing <a href="https://github.com/bearcove/merde_json">merde_json</a>,
<a href="https://github.com/bearcove/rubicon">rubicon</a> and others, I got a divorce in 2023, I found a new business model.</p>
<p data-bo="665">Now that we're on the same page: let's unpack this a bit!</p>
Face cams: the missing guidehttps://fasterthanli.me/articles/face-cams-the-missing-guide2024-03-02T18:00:00Z<p data-bo="129">I try to avoid doing "meta" / "behind the scenes" stuff, because I usually feel
like it has to be "earned". How many YouTube channels are channels about making
YouTube videos? Too many.</p>
<p data-bo="316">Regardless, because I've had the opportunity to make my own mistakes now for a
few years (I started <a href="https://www.youtube.com/@fasterthanlime">doing the video thing</a> in earnest in 2019), and because I've recently made a few leaps
in quality-of-life re: shooting and editing video, I thought I'd publish a few
notes, if only for reference for my future self.</p>
Just paying Figma $15/month because nothing else fucking workshttps://fasterthanli.me/articles/just-paying-figma-15-dollars2023-10-19T16:50:00Z<p data-bo="168">My family wasn't poor by any stretch of the imagination, but I was raised to
avoid spending money whenever possible.</p>
<p data-bo="286">I was also taught "it's a poor craftsman that blames their tools", which
apparently means "take responsibility for your fuckups", but, to young-me,
definitely sounded more like "you don't deserve nice things".</p>
<p data-bo="497">I was also taught from an early age that I was born a sinner, incapable of doing
good by myself, and that all the earthly things were temptations, sent by the
devil to corrupt me (further I guess?) but also temporary, and that I shouldn't
attach myself.</p>
Cracking Electron apps openhttps://fasterthanli.me/articles/cracking-electron-apps-open2023-07-03T16:30:00Z<p data-bo="148">I use the <a href="https://github.com/jgraph/drawio-desktop">draw.io desktop app</a> to
make diagrams for my website. I run it on an actual desktop, like Windows or
macOS, but the asset pipeline that converts <code>.drawio</code> files, to <code>.pdf</code>, to
<code>.svg</code>, and then to <code>.svg</code> again (but smaller) runs on Linux.</p>
<p data-bo="440">So I have a Rust program somewhere that opens headless chromium, and loads just
the HTML/JS/CSS part of draw.io I need to render my diagrams, and then use
Chromium's "print to PDF" functionality to save a PDF.</p>
The RustConf Keynote Fiasco, explainedhttps://fasterthanli.me/articles/the-rustconf-keynote-fiasco-explained2023-05-31T21:00:00Z<div class="disclosure paragraph-like">
<p data-bo="41"><strong>Disclaimer</strong>:</p>
<p data-bo="172">At some point in this article, I discuss The Rust Foundation. I have received a
$5000 grant from them in 2023 for making educational articles and videos about
Rust.</p>
<p data-bo="345">I have NOT signed any non-disclosure, non-disparagement, or any other sort of
agreement that would prevent me from saying exactly how I feel about their
track record.</p>
</div><div class="disclosure paragraph-like">
<p data-bo="41"><strong>Disclaimer</strong>:</p>
<p data-bo="537">I was part of the RustConf program committee in 2022, but not in 2023. More on
that later.</p>
</div>
Rust: The wrong people are resigninghttps://fasterthanli.me/articles/rust-the-wrong-people-are-resigning2023-05-28T17:04:00Z<p data-bo="114">(Note: this was originally posted <a href="https://gist.github.com/fasterthanlime/42da9378768aebef662dd26dddf04849">as a
gist</a>)</p>
<a id="reassuring-myself-about-rust" href="#reassuring-myself-about-rust" class="anchor"><h2>Reassuring myself about Rust</h2></a>
<p data-bo="268">Up until recently, I was part of two private online discussion spaces where a
bunch of Rust people hung out.</p>
<p data-bo="378">So, whenever there was drama, like when the entire mod team resigned, or when a
trademark draft got a lot of people seriously worried, or just recently when
<a href="https://thephd.dev/i-am-no-longer-speaking-at-rustconf-2023">RustConf took back the keynote from
ThePHD</a> then <a href="https://www.sophiajt.com/why-i-left-rust/">Sophia
resigned over it</a> and , I had some
place to go, to assess how serious things were this time around.</p>
Extra credithttps://fasterthanli.me/series/building-a-rust-service-with-nix/part-122023-03-05T07:30:12Z<p data-bo="104">We've achieved our goals already with this series: we have a web service written
in Rust, built into a Docker image with nix, with a nice dev shell, that we can
deploy to <a href="https://fly.io">fly.io</a>.</p>
<p data-bo="302">But there's always room for improvement, and so I wanted to talk about a few
things we didn't bother doing in the previous chapters.</p>
<a id="making-clash-geoip-available-in-the-dev-shell" href="#making-clash-geoip-available-in-the-dev-shell" class="anchor"><h2>Making <code>clash-geoip</code> available in the dev shell</h2></a>
<p data-bo="488">When we ran our app locally, we signed up for a MaxMindDB account, and had to
download and unpack the "Country" Geolite2 database manually.</p>
Generating a docker image with nixhttps://fasterthanli.me/series/building-a-rust-service-with-nix/part-112023-03-05T07:30:11Z<p data-bo="126">There it is. The final installment.</p>
<p data-bo="163">Over the course of this series, we've built a <em>very useful</em> Rust web service
that shows us colored ASCII art cats, and we've packaged it with docker, and
deployed it to <a href="https://fly.io">https://fly.io</a>.</p>
<p data-bo="351">We did all that without using <code>nix</code> at all, and then in the last few chapters,
we've learned to use <code>nix</code>, and now it's time to tell <code>docker build</code> goodbye,
along with this whole-ass :</p>
Making a dev shell with nix flakeshttps://fasterthanli.me/series/building-a-rust-service-with-nix/part-102023-03-05T07:30:10Z<p data-bo="117">In the previous chapter, we've made a nix "dev shell" that contained the fly.io
command-line utility, "flyctl".</p>
<p data-bo="230">That said, that's not how I want us to define a dev shell.</p>
<p data-bo="290">Our current solution has issues. I don't like that it has <code>import <nixpkgs></code>.
Which version of <code>nixpkgs</code> is that? The one you're on? Who knows what that is.</p>
<p data-bo="448">Also, we haven't really seen a mechanism to use files from elsewhere.</p>
Learning Nix from the bottom uphttps://fasterthanli.me/series/building-a-rust-service-with-nix/part-92023-03-05T07:30:09Z<p data-bo="114">Remember the snapshot we made allll the way back in <a href="part-1">Part 1</a>? Now's the time to use it.</p>
<p data-bo="211">Well, make sure you've committed and pushed all your changes, but when you're
ready, let's go back in time to before we installed anything catscii-specific in
our VM.</p>
<p data-bo="379">This should emulate the experience of a colleague onboarding onto the project
well enough!</p>
<p data-bo="471">(I didn't actually use VirtualBox's snapshot feature for this, I actually set up
a Ubuntu 22.10 VM on another computer entirely, but the effect should be much
the same).</p>
Doing geo-location and keeping analyticshttps://fasterthanli.me/series/building-a-rust-service-with-nix/part-82023-03-05T07:30:08Z<p data-bo="156">I sold you on some additional functionality for <code>catscii</code> last chapter, and we
got caught up in private registry / docker shenanigans, so, now, let's resume
web development as promised.</p>
<a id="adding-geolocation" href="#adding-geolocation" class="anchor"><h2>Adding geolocation</h2></a>
<p data-bo="366">We kinda left the <code>locat</code> crate stubby, it doesn't <em>actually</em> do any IP to
location lookups. It doesn't even have a dependency on a crate that <em>can</em> do
that.</p>
<p data-bo="525">So, let's do that. We'll use the
crate, which can read the MaxMind DB format, like GeoIP2 and GeoLite2:</p>
Using the Shipyard private crate registry with Dockerhttps://fasterthanli.me/series/building-a-rust-service-with-nix/part-72023-03-05T07:30:07Z<div class="dialog bear">
<div class="dialog-head" title="Cool bear says:">
<picture>
<source type="image/jxl" srcset="https://cdn.fasterthanli.me/content/img/reimena/cool-bear-neutral~318815444a238722.jxl">
<source type="image/avif" srcset="https://cdn.fasterthanli.me/content/img/reimena/cool-bear-neutral~855ba1f506e3aa13.avif">
<source type="image/webp" srcset="https://cdn.fasterthanli.me/content/img/reimena/cool-bear-neutral~1cd56ba16f658405.webp">
<img src="https://cdn.fasterthanli.me/content/img/reimena/cool-bear-neutral~318815444a238722.jxl" class="bear" width="42" height="42" alt="Cool bear">
</picture>
</div>
<div class="dialog-text markup-container">
<p data-bo="179">Wait wait wait, so we're not talking about nix yet?</p>
</div>
</div><p data-bo="232">Well, no! The service we have is pretty simple, and I want to complicate things
a bit, to show how things would work in both the Dockerfile and the nix
scenario.</p>
<p data-bo="395">And because I don't like contrived examples, we're going to do something
somewhat real-world: we're going to geo-locate visitors, and track how many
visits we get from each country.</p>
Deploying catscii to fly.iohttps://fasterthanli.me/series/building-a-rust-service-with-nix/part-62023-03-05T07:30:06Z<div class="disclosure paragraph-like">
<p data-bo="41"><strong>Disclaimer</strong>:</p>
<p data-bo="153">Because I used to work for fly.io, I still benefit from an employee discount
at the time of this writing: I don't have to pay for anything deployed there
for now.</p>
<p data-bo="324">fly.io is still <a href="/donate">sponsoring me</a> for developing
<a href="https://github.com/hapsoc/hring">hring</a>, but this isn't a sponsored post. It's
just a good fit for what we're doing here, with a generous free tier.</p>
</div><p data-bo="535">In the <a href="part-5">previous chapter</a>, we've written a to build the
service inside Docker. The result is a container image that can be
pushed to production!</p>
Writing a Dockerfile for catsciihttps://fasterthanli.me/series/building-a-rust-service-with-nix/part-52023-03-05T07:30:05Z<p data-bo="127">Now that our service is production-ready, it's time to deploy it somewhere.</p>
<p data-bo="204">There's a lot of ways to approach this: what we are going to do, though, is
build a docker image. Or, I should say, an <a href="https://github.com/opencontainers/image-spec">OCI
image</a>.</p>
<p data-bo="383">This is still a series about Nix, but again: because the best way to see the
benefits of Nix is to do it <em>without</em> Nix first, we'll use only Docker's tooling
to build the image.</p>
<a id="installing-docker-on-ubuntu" href="#installing-docker-on-ubuntu" class="anchor"><h2>Installing Docker on Ubuntu</h2></a>
Serving ASCII cats over HTTPhttps://fasterthanli.me/series/building-a-rust-service-with-nix/part-42023-03-05T07:30:04Z<p data-bo="146">Our <code>catscii</code> program does everything we want it to do, except that it's a
command-line application rather than a web server. Let's fix that.</p>
<a id="enter-axum" href="#enter-axum" class="anchor"><h2>Enter <code>axum</code></h2></a>
<p data-bo="306">The documentation for the <a href="https://crates.io/crates/axum">axum</a> crate tells us how
to make a basic web server, and we honestly don't need much more than that.</p>
<p data-bo="466">So let's add axum:</p>
<code class="code-block has-language-tag" translate="no" data-lang="shell""><label class="language-tag" title="Shell session"></label><pre class="scroll-wrapper">amos@miles:~/catscii$ cargo add [email protected]
Updating crates.io index
Adding axum =0.6 to dependencies.
Features:
+ form
+ http1
+ json
+ matched-path
+ original-uri
+ query
+ tokio
+ tower-log
- __private_docs
- headers
- http2
- macros
- multipart
- w
</pre></code>
Printing ASCII cats to the terminalhttps://fasterthanli.me/series/building-a-rust-service-with-nix/part-32023-03-05T07:30:03Z<p data-bo="131">Now that our development environment is all set up, let's make something useful!</p>
<a id="creating-the-catscii-crate" href="#creating-the-catscii-crate" class="anchor"><h2>Creating the <code>catscii</code> crate</h2></a>
<p data-bo="246">From a VS Code window connected to our VM (as we <a href="part-2">just set up</a>), let's
make a new Rust project:</p>
<code class="code-block has-language-tag" translate="no" data-lang="shell""><label class="language-tag" title="Shell session"></label><pre class="scroll-wrapper">amos@miles:~$ cargo new catscii
Created binary (application) `catscii` package
</pre></code><p data-bo="449">And open it in a new VSCode window:</p>
<code class="code-block has-language-tag" translate="no" data-lang="shell""><label class="language-tag" title="Shell session"></label><pre class="scroll-wrapper">amos@miles:~$ code catscii
</pre></code><p data-bo="527">Even though we're running this "code" command in the VM guest, VSCode set up
enough plumbing that it communicates back to the host, telling it to open
another VSCode window, connected to the same SSH remote, in the right folder.</p>
Developing over SSHhttps://fasterthanli.me/series/building-a-rust-service-with-nix/part-22023-03-05T07:30:02Z<p data-bo="113">With <a href="part-1">the previous part</a>'s VM still running, let's try connecting to our
machine over SSH.</p>
<a id="network-addresses-loopback-and-ip-nets" href="#network-addresses-loopback-and-ip-nets" class="anchor"><h2>Network addresses, loopback and IP nets</h2></a>
<p data-bo="257">Normally, to connect to a machine, you'd find its IP address. On Linux, a decade
ago, you would've used <code>ifconfig</code>. Nowadays you can use <code>ip addr</code>:</p>
<p data-bo="406"><picture><source type="image/jxl" srcset="https://cdn.fasterthanli.me/content/series/building-a-rust-service-with-nix/part-2/assets/ip-addr~91ed63cb9a392561.jxl"><source type="image/avif" srcset="https://cdn.fasterthanli.me/content/series/building-a-rust-service-with-nix/part-2/assets/ip-addr~e5c07383ef672e97.avif"><source type="image/webp" srcset="https://cdn.fasterthanli.me/content/series/building-a-rust-service-with-nix/part-2/assets/ip-addr~dfb6487be8cd875d.webp"><img src="https://cdn.fasterthanli.me/content/series/building-a-rust-service-with-nix/part-2/assets/ip-addr~91ed63cb9a392561.jxl" loading="lazy" width="800" height="600" title="The ip addr command output, run in VirtualBox" alt="The ip addr command output, run in VirtualBox"></picture></p>
<p data-bo="476">The loopback interface (<code>lo</code>) is local, so it's not useful to reach the box from
the outside: you can see it can be accessed over IPv4 at address 127.0.0.1 but
not just! What we're reading here is 127.0.0.1/8, which corresponds to the range
</p>
Setting up a local Ubuntu Server VMhttps://fasterthanli.me/series/building-a-rust-service-with-nix/part-12023-03-05T07:30:01Z<p data-bo="136">The first step to using Nix to build Rust is to do so <em>without</em> Nix, so that
when we finally do, we can feel the difference.</p>
<p data-bo="262">There's many ways to go about this: everyone has their favorite code editor,
base Linux distribution (there's even a <a href="https://nixos.org/">NixOS</a>
distribution, which I won't cover). Some folks like to develop on macOS first,
and <em>then</em> build for Linux.</p>
<p data-bo="515">Y'all are all valid, but for this series, we're going to very specifically do
what I before nix, and what I'm doing now that I've embraced my 30s
and become "a nix person", and we'll evaluate the ups and downsides of both
approaches.</p>
The bottom emoji breaks rust-analyzerhttps://fasterthanli.me/articles/the-bottom-emoji-breaks-rust-analyzer2023-02-13T14:20:00Z<p data-bo="131">Some bugs are merely fun. Others are simply delicious!</p>
<p data-bo="187">Today's pick is the latter.</p>
<a id="reproducing-the-issue-part-1" href="#reproducing-the-issue-part-1" class="anchor"><h2>Reproducing the issue, part 1</h2></a>
<p data-bo="250">(It may be tempting to skip that section, but reproducing an issue is an important
part of figuring it out, so.)</p>
<p data-bo="364">I've never used Emacs before, so let's install it. I do most of my computing
on an era-appropriate Ubuntu, today it's Ubuntu 22.10, so I just need to:</p>
<code class="code-block has-language-tag" translate="no" data-lang="shell""><label class="language-tag" title="Shell session"></label><pre class="scroll-wrapper">$ sudo apt install emacs-nox
</pre></code>
Day 18 (Advent of Code 2022)https://fasterthanli.me/series/advent-of-code-2022/part-182023-01-12T14:00:00Z<p data-bo="139">This time around, we're porting a solution from C++ to Rust and seeing how it
feels, how it performs, and what we can learn about both languages by doing that.</p>
<p data-bo="300">See <a href="part-17">Day 17</a> for the rationale re: porting solutions rather than
writing my own from scratch. TL;DR is: it's better than nothing, and we can
still focus about learning Rust rather than spending entire days fighting
off-by-one errors.</p>
<p data-bo="544">The research for this article was done live on stream, I'm not going to cover
everything in the write-up, so check it out if you want the full experience:</p>
Twitch fell behindhttps://fasterthanli.me/articles/twitch-fell-behind2023-01-12T13:00:00Z<p data-bo="125">So you want to do live streams. Are you sure? Okay. Let's talk about it.</p>
<a id="let-s-talk-numbers" href="#let-s-talk-numbers" class="anchor"><h2>Let's talk numbers</h2></a>
<p data-bo="222">Being a "content creator" (sorry for those who hate that term) <em>is</em> a job, for
sure, and many people do it, successfully, full-time, they pay rent with it etc.</p>
<p data-bo="383">Platforms like Twitch & YouTube would have you think that, if you put in enough
effort, you can grow your channel from nothing to 🎉 profitable ✨ in just a few
short years.</p>
Day 17 (Advent of Code 2022)https://fasterthanli.me/series/advent-of-code-2022/part-172023-01-11T15:00:00Z<p data-bo="142">Advent of Code gets harder and harder, and I'm not getting any smarter. Or any
more free time. So, in order to close out this series anyway, I'm going to try
and port other people's solutions from "language X" to Rust. That way, they
already figured out the hard stuff, and we can just focus on the Rust bits!</p>
<p data-bo="453">Sounds good? Good. Let's proceed.</p>
<p data-bo="488">The research for this article was done live on
and
, if you'd rather watch me
go through it step by step, you can watch the VOD below:</p>
Day 16 (Advent of Code 2022)https://fasterthanli.me/series/advent-of-code-2022/part-162022-12-29T15:00:00Z<p data-bo="131">Let's tackle the <a href="https://adventofcode.com/2022/day/16">day 16 puzzle</a>!</p>
<a id="parsing" href="#parsing" class="anchor"><h2>Parsing</h2></a>
<p data-bo="216">The input looks like this:</p>
<code class="code-block" translate="no" data-lang="""><pre class="scroll-wrapper">Valve AA has flow rate=0; tunnels lead to valves DD, II, BB
Valve BB has flow rate=13; tunnels lead to valves CC, AA
Valve CC has flow rate=2; tunnels lead to valves DD, BB
Valve DD has flow rate=20; tunnels lead to valves CC, AA, EE
Valve EE has flow rate=3; tunnels lead to valves FF, DD
Valve FF has flow rate=0; tunnels lead to valves EE, GG
Valve GG has flow rate=0; tunnels lead to valves FF, HH
Valve HH has flow rate=22; tunnel leads to valve GG
Valve II has flow rate=0; tunnels lead to valves AA, JJ
Valve JJ has flow rate=21; tunnel leads to valve II
</pre></code>