<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.8.5">Jekyll</generator><link href="/feed.xml" rel="self" type="application/atom+xml" /><link href="/" rel="alternate" type="text/html" /><updated>2019-11-12T21:06:31+00:00</updated><id>/feed.xml</id><title type="html">Moritz Clasmeier</title><subtitle>Haskell, Hacking</subtitle><author><name>Moritz Clasmeier</name></author><entry><title type="html">Rustberry Jukebox</title><link href="/2019/11/12/rustberry-jukebox/" rel="alternate" type="text/html" title="Rustberry Jukebox" /><published>2019-11-12T00:00:00+00:00</published><updated>2019-11-12T00:00:00+00:00</updated><id>/2019/11/12/rustberry-jukebox</id><content type="html" xml:base="/2019/11/12/rustberry-jukebox/">&lt;p&gt;So, I am one of those tech-affine parents, who wanted to build some kind of Jukebox device for
their child. In this post I provide an overview of my specific jukebox implementation.&lt;/p&gt;

&lt;p&gt;There are &lt;a href=&quot;https://tonies.de/&quot;&gt;commercial products&lt;/a&gt; and existing &lt;a href=&quot;http://phoniebox.de/index-en.html&quot;&gt;hobbyist
projects&lt;/a&gt;, but for several reasons I decided
to work on my own project. It is called &lt;em&gt;Rustberry Jukebox&lt;/em&gt; and the core
software is written in &lt;a href=&quot;https://www.rust-lang.org&quot;&gt;Rust&lt;/a&gt;. Even though the name
might suggest otherwise, please note that this is not related to an existing
Rust &lt;a href=&quot;https://crates.io/crates/rustberry&quot;&gt;crate&lt;/a&gt; with a similar name.&lt;/p&gt;

&lt;p&gt;The feature set I had in mind for the jukebox device:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Rustic/old aesthetics (as opposed to the polished modern interface of commercial products)&lt;/li&gt;
  &lt;li&gt;Stream music from Spotify via WLAN&lt;/li&gt;
  &lt;li&gt;Playback controllable via RFID tags&lt;/li&gt;
  &lt;li&gt;Hardware button for switching the jukebox on and off&lt;/li&gt;
  &lt;li&gt;Status LEDs (jukebox running and jukebox playing)&lt;/li&gt;
  &lt;li&gt;The code should be conveniently cross-compilable for a Raspberry Pi.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the resulting jukebox:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/jukebox-open.jpg&quot;&gt;&lt;img src=&quot;/assets/images/jukebox-open.jpg&quot; alt=&quot;Jukebox Open&quot; style=&quot;width:30%;&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/assets/images/jukebox-open-2.jpg&quot;&gt;&lt;img src=&quot;/assets/images/jukebox-open-2.jpg&quot; alt=&quot;Jukebox Open&quot; style=&quot;width:40%;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let us now have a closer look.&lt;/p&gt;

&lt;h2 id=&quot;components&quot;&gt;Components&lt;/h2&gt;

&lt;h3 id=&quot;the-case&quot;&gt;The Case&lt;/h3&gt;

&lt;p&gt;I am pretty unexperienced when it
comes to physical manufacturing. Fortunately I found a potential enclosing, which seemed
promising: an old looking &lt;a href=&quot;https://www.amazon.de/BRYNNBERG-Schatztruhe-Marco-38x27x14cm-Aufbewahrungsbox/dp/B07CMPTSD9/ref=sr_1_3?__mk_de_DE=%C3%85M%C3%85%C5%BD%C3%95%C3%91&amp;amp;crid=2X2CTDPJTEGAA&amp;amp;keywords=holzkiste+verschlie%C3%9Fbar&amp;amp;qid=1570263909&amp;amp;s=kitchen&amp;amp;sprefix=holzkiste+vers%2Ckitchen%2C165&amp;amp;sr=1-3&quot;&gt;suitcase / treasure
chest&lt;/a&gt;.
I thought it might be feasible to build a double bottom into this suitcase,
having enough hidden space for all the tech stuff inside (Raspberry Pi,
speakers, power, circuits, cables / adapters) and providing enough space above
the double bottom for user controls and RFID-equipped &lt;em&gt;records&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/jukebox-suitcase.jpg&quot;&gt;&lt;img src=&quot;/assets/images/jukebox-suitcase.jpg&quot; alt=&quot;Jukebox Suitcase&quot; style=&quot;width:40%;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;the-records&quot;&gt;The Records&lt;/h3&gt;

&lt;p&gt;What should the RFID tags be attached to, if one does not want to use plain RFID
cards or transponders? Again, I was lucky to find a product, which
matches the intended rustic aesthetics and allows for cheap extensibility:
&lt;a href=&quot;https://www.amazon.de/gp/product/B078HB4ZD7/ref=ppx_yo_dt_b_asin_title_o06_s00?ie=UTF8&amp;amp;language=en_GB&amp;amp;psc=1&quot;&gt;wooden
discs&lt;/a&gt;.
The idea is to stick the RFID tag to the bottom side of a disk and use the top
side for artwork.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/jukebox-records.jpg&quot;&gt;&lt;img src=&quot;/assets/images/jukebox-records.jpg&quot; alt=&quot;Jukebox Records&quot; style=&quot;width:40%;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;the-tech&quot;&gt;The Tech&lt;/h3&gt;

&lt;p&gt;I had an old Raspberry Pi 2 laying around, which I intended to use as a
technological foundation for the jukebox. The playback should be controllable
via RFID tags – a technology, which I am not familiar with at all. After some
research I had identified the &lt;a href=&quot;http://wiki.sunfounder.cc/index.php?title=Mifare_RC522_Module_RFID_Reader&quot;&gt;MIFARE
RC522&lt;/a&gt;
as a common and well-supported RFID reader/writerfor suitable for &lt;a href=&quot;https://pimylifeup.com/raspberry-pi-rfid-rc522/&quot;&gt;use with a
Raspberry Pi&lt;/a&gt;. This device is
compatible with RFID tags such as &lt;a href=&quot;https://www.amazon.de/gp/product/B01HEU96C6&quot;&gt;MIFARE Classic 1K Chip,
13.56mhz&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For enabling audio output, I went with the &lt;a href=&quot;https://www.amazon.de/gp/product/B00JRW0M32&quot;&gt;Trust Leto 2.0 USB
Speakers&lt;/a&gt;. I was somewhat worried
about the energy consumption (6W) of these speakers, since I prefer to not use
additional power sources besides the Raspberry Pi’s own USB connectors for
compactness reasons. But they seem to work fine at medium volume. The USB speakers connect to
the computer via a standard stereo jack, but as is well-known the stereo jack
output of the Raspberry Pi offers poor quality. Therefore I have decided to
extract the audio signal from the Raspberry HDMI output using a simple
&lt;a href=&quot;https://www.amazon.de/gp/product/B00ZMV7RL2&quot;&gt;HDMI-to-VGA adapter&lt;/a&gt; capable of
extracting the HDMI audio signal.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/jukebox-inner.jpg&quot;&gt;&lt;img src=&quot;/assets/images/jukebox-inner.jpg&quot; alt=&quot;Jukebox Inner&quot; style=&quot;width:40%;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;the-software&quot;&gt;The Software&lt;/h2&gt;

&lt;p&gt;As mentioned above there are already software solutions for an
RFID-controllable jukebox. But after a quick look at the &lt;a href=&quot;https://www.phoniebox.de&quot;&gt;Phoniebox&lt;/a&gt; software &lt;a href=&quot;https://github.com/MiczFlor/RPi-Jukebox-RFID&quot;&gt;RPi-Jukebox-RFID&lt;/a&gt; I decided to build my
&lt;a href=&quot;https://github.com/mtesseract/rustberry&quot;&gt;own project&lt;/a&gt;. The primary motives for this decision include the following:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;RPi-Jukebox-RFID seems like a rather huge Python project and I am neither particularly familiar
with Python tooling, nor with the Python ecosystem. Also, I have not had the best experiences with Python
codebases in the past, though I cannot judge about the quality of this
particular project.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Currently I am primarily interested in one particular
use-case: Spotify integration – which is labelled as “experimental” for
RPi-Jukebox-RFID. I wanted something more compact and simple.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;From the introductory video of the Phoniebox it seems that the RFID-control
logic is such that an RFID tag is used only for &lt;em&gt;triggering&lt;/em&gt; playback. What I
would prefer is that an RFID tag is used for controlling the playback, which
means &lt;em&gt;starting&lt;/em&gt; and &lt;em&gt;stopping&lt;/em&gt; it, similar to the commercial Toniebox:
Playback is active as long as the RFID tag is in range of the RFID reader.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After evaluation of a few options I decided to build the software with Rust,
since I learned to like that language, it performs well, has a great package
ecosystem, can be used for lower-level hardware access, comes with a low memory
footprint and it has a pretty good cross-compilation story. Besides, I have
never worked on a similar project and it seemed like an interesting learning opportunity.&lt;/p&gt;

&lt;h3 id=&quot;spotify-playback&quot;&gt;Spotify Playback&lt;/h3&gt;

&lt;p&gt;Regarding Spotify Playback, my initial plan was to run Firefox on the Raspberry
Pi and use the &lt;a href=&quot;https://developer.spotify.com/documentation/web-playback-sdk/&quot;&gt;Spotify Web
SDK&lt;/a&gt; for
providing the Spotify streaming capabilities. This worked pretty well on my
development machine. But once I tried it out on the Raspberry I had learn the
hard way that the Spotify Web SDK requires Widevine DRM Support, which the
non-official Firefox builds do not contain (and for ARM there are no official
Firefox builds). So this was my daily lesson in the category “Integrate early”.
So, how do I stream from Spotify? Well,
&lt;a href=&quot;https://github.com/librespot-org/librespot&quot;&gt;Librespot&lt;/a&gt; comes to the rescue:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;librespot is an open source client library for Spotify. It enables
applications to use Spotify’s service, without using the official but
closed-source libspotify. Additionally, it will provide extra features which
are not available in the official library.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Librespot is used and packaged by the
&lt;a href=&quot;https://github.com/dtcooper/raspotify&quot;&gt;Raspotify&lt;/a&gt; project. They provide easy to
install Debian packages for ARM Raspbian. With Raspotify installed and
configured to use a specific Spotify Premium account, the Raspberry is ready to
be used as Spotify client through the &lt;a href=&quot;https://developer.spotify.com/documentation/web-api/&quot;&gt;Spotify Web
API&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;os&quot;&gt;OS&lt;/h3&gt;

&lt;p&gt;Actually I would have preferred being able to use &lt;a href=&quot;https://nixos.org/&quot;&gt;NixOS&lt;/a&gt; on the Raspberry Pi, but
unfortunately the ARM port of NixOS was way to rough around the edges for my use-case. The issues I
have had with NixOS even on my Raspberry Pi 3, which comes with an AARCH64 CPU
somewhat supported by upstream NixOS, included:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Missing and/or incomplete documentation, in particular when it comes to
configuring the Raspberry Pi firmware and the boot process (after having
written a first &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;configuration.nix&lt;/code&gt; according to the documentation, the
Raspberry Pi was unable to boot).&lt;/li&gt;
  &lt;li&gt;The boot process is slower than Raspbian’s.&lt;/li&gt;
  &lt;li&gt;After about 2h work I was still not able to get audio working – something
that just works on Raspbian.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With NixOS I like being able to declaratively configure the complete operating
system with all required services and deploy a system configuration to a remote
NixOS with complete rollback functionality built-in.  Maybe somewhen in the
future I can write the NixOS derivations for my Jukebox Software and deploy it
to a Raspberry Pi running NixOS. But this is not today.&lt;/p&gt;

&lt;p&gt;Given this unsatisfying situation I have decided to build on &lt;strong&gt;Raspbian&lt;/strong&gt;.&lt;/p&gt;

&lt;h3 id=&quot;rfid-io&quot;&gt;RFID IO&lt;/h3&gt;

&lt;p&gt;A quick search on &lt;a href=&quot;&quot;&gt;crates.io&lt;/a&gt; revealed the following list of potentially useful crates:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://crates.io/crates/rfid-rs&quot;&gt;rfid-rs&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://crates.io/crates/mfrc522&quot;&gt;mfrc522&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It seems that &lt;em&gt;mfrc522&lt;/em&gt; is currently very limited in functionality (see
https://docs.rs/mfrc522/0.2.0/mfrc522/struct.Mfrc522.html) and does not yet
support reading and writing the data blocks on an RFID tag. &lt;em&gt;rfid-rs&lt;/em&gt; on the
other side does
support reading from and writing to the RFID tag’s data blocks, but the &lt;a href=&quot;https://gitlab.com/jspngh/rfid-rs&quot;&gt;upstream code
base&lt;/a&gt; had some issues, which is why I have
created my &lt;a href=&quot;https://gitlab.com/mclasmeier/rfid-rs&quot;&gt;personal fork&lt;/a&gt; for the
purpose of this project. I will see if my changes can be integrated into the
upstream version of the crate.&lt;/p&gt;

&lt;h3 id=&quot;gpio&quot;&gt;GPIO&lt;/h3&gt;

&lt;p&gt;For GPIO access there are multiple crates available, for example:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://crates.io/crates/gpio-cdev&quot;&gt;gpio-cdev&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://crates.io/crates/gpio&quot;&gt;gpio&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://crates.io/crates/sysfs_gpio&quot;&gt;sysfs_gpio&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I have decided to go with &lt;em&gt;gpio-cdev&lt;/em&gt;, since – according to my understanding – using the character device API for GPIO is
recommended for new applications. I have been missing some built-in functionality for
listening for events on mutliple GPIO lines at the same time, but that was easy
to implement using threads and channels.&lt;/p&gt;

&lt;p&gt;At some point I had confused the different GPIO line labeling systems. For debugging GPIO, the following command turned out to be very helpful:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;watch -d -n 0.5 gpio -g readall
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;(the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gpio&lt;/code&gt; program comes from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wiringpi&lt;/code&gt; package)&lt;/p&gt;

&lt;h2 id=&quot;circuits&quot;&gt;Circuits&lt;/h2&gt;

&lt;p&gt;For the first vesion of the Jukebox the following hardware related functionality should be be supported:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;A single physical button for switching the box on and shutting it down.&lt;/li&gt;
  &lt;li&gt;Stable RFID tag reading via the RC522 reader.&lt;/li&gt;
  &lt;li&gt;A status LED indicating that the box is running.&lt;/li&gt;
  &lt;li&gt;A status LED for indicating that it is in playback mode (i.e. an RFID tag is
near the RFID reader).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;power-switch&quot;&gt;Power Switch&lt;/h3&gt;

&lt;p&gt;I found &lt;a href=&quot;https://howchoo.com/g/mwnlytk3zmm/how-to-add-a-power-button-to-your-raspberry-pi&quot;&gt;an article&lt;/a&gt;, which describes
the wake-up functionality:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Simply put, shorting pins 5 and 6 (GPIO3 and GND) together will wake the Pi up from a halt state.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As indicated above, there should be a single physical button for switching the
device on and shutting it down. Therefore, it is already clear that the power
button needs to be connected to GPIO3, which needs to be configured as an input
line. Since pressing the button is required to connect GPIO3 with GND, the
GPIO3 line needs to be set to high when the button is &lt;em&gt;not&lt;/em&gt; pressed. In other
words, we need a &lt;a href=&quot;https://en.wikipedia.org/wiki/Pull-up_resistor&quot;&gt;Pull-up
resistor&lt;/a&gt; connecting GPIO3
through a resistor with a voltage source when the button is not pressed. When
the button is pressed GPIO3 will be connected with GND.&lt;/p&gt;

&lt;h3 id=&quot;power-status-led&quot;&gt;Power Status LED&lt;/h3&gt;

&lt;p&gt;There is a nice hack for building a status LED: Connect a LED to the Raspberry
Pi’s serial console as described in the article &lt;a href=&quot;https://howchoo.com/g/ytzjyzy4m2e/build-a-simple-raspberry-pi-led-power-status-indicator&quot;&gt;Build a Simple Raspberry Pi LED
Power/Status
Indicator&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;playback-status-led&quot;&gt;Playback Status LED&lt;/h3&gt;

&lt;p&gt;This is nothing fancy, just another LED conneted to a regular GPIO input line,
which is configured as output and controlled in software.&lt;/p&gt;

&lt;h2 id=&quot;cross-compilation&quot;&gt;Cross Compilation&lt;/h2&gt;

&lt;p&gt;I am currently developing on Darwin/x86_64, but the Raspberry Pi runs
Linux/ARMv7. I have created a &lt;a href=&quot;https://github.com/mtesseract/rustberry/blob/master/builder/Dockerfile&quot;&gt;Docker image
description&lt;/a&gt;,
for a build container. The container contains the cross-compilation toolchain
and is reachable via SSH.
A &lt;a href=&quot;https://github.com/mtesseract/rustberry/blob/master/builder/build.sh&quot;&gt;build
script&lt;/a&gt; is
used for producing binaries of the Rustberry Jukebox software for the Raspberry
Pi.&lt;/p&gt;</content><author><name>Moritz Clasmeier</name></author><summary type="html">So, I am one of those tech-affine parents, who wanted to build some kind of Jukebox device for their child. In this post I provide an overview of my specific jukebox implementation.</summary></entry><entry><title type="html">Nixified Jekyll setup</title><link href="/2019/01/29/nixified-jekyll/" rel="alternate" type="text/html" title="Nixified Jekyll setup" /><published>2019-01-29T00:00:00+00:00</published><updated>2019-01-29T00:00:00+00:00</updated><id>/2019/01/29/nixified-jekyll</id><content type="html" xml:base="/2019/01/29/nixified-jekyll/">&lt;p&gt;What I particularly like about Nix is its ability to &lt;em&gt;encapsulate&lt;/em&gt; environments. No need to remember how to set up a certain environment, just encode it in a Nix expression, check it into version control and use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nix-shell&lt;/code&gt;. This is especially useful when having to occasionally deal with certain environments, without being too familiar with the technical details. For me one such example is Jekyll, a Ruby application (and I am not familiar with Ruby).&lt;/p&gt;

&lt;p&gt;I have created a new Jekyll blog and used &lt;a href=&quot;https://github.com/manveru/bundix&quot;&gt;bundix&lt;/a&gt; to convert a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Gemfile&lt;/code&gt; into a Nix expression (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gemset.nix&lt;/code&gt;). To this, add the following &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;default.nix&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-nix highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;nixpkgs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{});&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;ghPagesEnv&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;bundlerEnv&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;mtesseract-github-pages-env&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;inherit&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ruby&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;gemdir&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;./.&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;in&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;shell&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;stdenv&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;mkDerivation&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;mtesseract-github-pages&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;buildInputs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ghPagesEnv&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;serve&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;stdenv&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;mkDerivation&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;mtesseract-github-pages-serve&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;buildInputs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ghPagesEnv&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;shellHook&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;      exec &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ghPagesEnv&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/bin/jekyll serve --watch&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;    ''&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This expression contains two attributes: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;shell&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;serve&lt;/code&gt;. Thus, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nix-shell -A shell&lt;/code&gt; spawns an interactive shell having Jekyll in path, while &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nix-shell -A serve&lt;/code&gt; spawn Jekyll to serve the page at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://localhost:4000&lt;/code&gt;. For details, check out the &lt;a href=&quot;http://github.com/mtesseract/mtesseract.github.io&quot;&gt;repository&lt;/a&gt; of this blog.&lt;/p&gt;</content><author><name>Moritz Clasmeier</name></author><summary type="html">What I particularly like about Nix is its ability to encapsulate environments. No need to remember how to set up a certain environment, just encode it in a Nix expression, check it into version control and use nix-shell. This is especially useful when having to occasionally deal with certain environments, without being too familiar with the technical details. For me one such example is Jekyll, a Ruby application (and I am not familiar with Ruby).</summary></entry><entry><title type="html">Deploying a Reflex Application to NixOS</title><link href="/2019/01/28/deploying-reflex-app-to-nixos/" rel="alternate" type="text/html" title="Deploying a Reflex Application to NixOS" /><published>2019-01-28T00:00:00+00:00</published><updated>2019-01-28T00:00:00+00:00</updated><id>/2019/01/28/deploying-reflex-app-to-nixos</id><content type="html" xml:base="/2019/01/28/deploying-reflex-app-to-nixos/">&lt;p&gt;In the following post I describe how a simple Haskell web application built on top of &lt;a href=&quot;https://github.com/reflex-frp&quot;&gt;Reflex FRP&lt;/a&gt; can be deployed to a remote &lt;a href=&quot;https://nixos.org/&quot;&gt;NixOS&lt;/a&gt; server. If a remote NixOS server is available using it for deployment can be cheaper alternative to commercial cloud providers in case the features of those (e.g. scaling, hosted services, availability guarantees, etc.) are not strictly required.&lt;/p&gt;

&lt;p&gt;The sample Reflex application can be found &lt;a href=&quot;https://github.com/mtesseract/reflex-app&quot;&gt;on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Our setting is as follows:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The application, consisting of a frontend and a backend, is built with Nix&lt;/li&gt;
  &lt;li&gt;The development system is a Mac (i.e., not &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x86_64-linux&lt;/code&gt;)&lt;/li&gt;
  &lt;li&gt;The application supports some trivial database access&lt;/li&gt;
  &lt;li&gt;The application is to be deployed to a remote server running NixOS (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x86_64-linux&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;the-application-skeleton&quot;&gt;The Application Skeleton&lt;/h2&gt;

&lt;p&gt;The application is based on the &lt;a href=&quot;https://github.com/reflex-frp/reflex-platform/blob/develop/docs/project-development.md&quot;&gt;project skeleton&lt;/a&gt; as documented as part of the &lt;a href=&quot;https://github.com/reflex-frp/reflex-platform&quot;&gt;Reflex Platform&lt;/a&gt;. It contains three Cabal projects (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;common&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frontend&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;backend&lt;/code&gt;) and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;reflex-platform&lt;/code&gt; as a Git submodule. Nix expressions are used for building the applications.&lt;/p&gt;

&lt;p&gt;In addition, there is a top-level directory &lt;a href=&quot;https://github.com/mtesseract/reflex-app/tree/master/deployment&quot;&gt;deployment&lt;/a&gt; containing the deployment relevant code.&lt;/p&gt;

&lt;h2 id=&quot;building-on-macos-for-linux&quot;&gt;Building on macOS for Linux&lt;/h2&gt;

&lt;p&gt;For deploying we want to transfer a complete build artifact, a Nix closure, to the remote server and activate it. Since the development computer is assumed to be running macOS and the application needs to be built for Linux (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x86_64-linux&lt;/code&gt;), we use Docker and the &lt;a href=&quot;https://github.com/LnL7/nix-docker&quot;&gt;nix-docker project&lt;/a&gt;. The included script &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;start-docker-nix-build-slave&lt;/code&gt; assists in setting up a Nix remote builder.&lt;/p&gt;

&lt;p&gt;The application skeletons needs a &lt;a href=&quot;https://github.com/reflex-frp/reflex-platform/pull/440&quot;&gt;tweak&lt;/a&gt; to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;default.nix&lt;/code&gt; expression in order to respect the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;system&lt;/code&gt; parameter.&lt;/p&gt;

&lt;h2 id=&quot;database-access&quot;&gt;Database Access&lt;/h2&gt;

&lt;p&gt;Our application server (the system on which the application frontend and backend will be deployed) runs in its own virtual machine managed via &lt;a href=&quot;https://libvirt.org/&quot;&gt;libvirt&lt;/a&gt;. In order to separate the stateless and stateful aspects of the deployment, we set up a dedicated database server VM, i.e. a NixOS server running PostgreSQL. The database server is not directly connected to the internet, instead the database server and the application server are connected via an &lt;a href=&quot;https://wiki.libvirt.org/page/Networking#NAT_forwarding_.28aka_.22virtual_networks.22.29&quot;&gt;internal bridge&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The NixOS configuration of the database server looks as follows:&lt;/p&gt;

&lt;div class=&quot;language-nix highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;pkgs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}:&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;imports&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;sx&quot;&gt;./hardware-configuration.nix&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;

  &lt;span class=&quot;nv&quot;&gt;boot&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;loader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;grub&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;enable&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;boot&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;loader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;grub&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;version&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;boot&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;loader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;grub&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;device&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/dev/vda&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;nv&quot;&gt;networking&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;hostName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;db&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;interfaces&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ens3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ipv4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;addresses&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;address&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;192.168.122.2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;prefixLength&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;24&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;nameservers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;8.8.8.8&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;defaultGateway&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;192.168.122.1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;firewall&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nv&quot;&gt;allowedTCPPorts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;22&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5432&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
      &lt;span class=&quot;nv&quot;&gt;enable&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

  &lt;span class=&quot;nv&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;timeZone&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Europe/Berlin&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;nv&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;systemPackages&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;pkgs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;vim&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;postgresql100&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;

  &lt;span class=&quot;nv&quot;&gt;services&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;ntp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nv&quot;&gt;enable&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;openssh&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nv&quot;&gt;enable&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;postgresql&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nv&quot;&gt;enable&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;nv&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;pkgs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;postgresql100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;nv&quot;&gt;enableTCPIP&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;nv&quot;&gt;authentication&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;pkgs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;lib&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;mkOverride&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;        local all all trust&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;        host all all 192.168.122.0/24 trust&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;        ''&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;nv&quot;&gt;initialScript&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;pkgs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;writeText&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;backend-initScript&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;        CREATE ROLE app WITH LOGIN PASSWORD 'app' CREATEDB;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;        CREATE DATABASE app;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;        GRANT ALL PRIVILEGES ON DATABASE app TO app;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;      ''&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;system&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;stateVersion&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;18.09&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;users&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;users&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;openssh&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;authorizedKeys&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;keys&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;ssh-rsa ...&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;noXlibs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;system&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;autoUpgrade&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;enable&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This configuration makes sure that a PostgreSQL role &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;app&lt;/code&gt; with the same password and database name is initially created.&lt;/p&gt;

&lt;h2 id=&quot;deploying&quot;&gt;Deploying&lt;/h2&gt;

&lt;p&gt;The Nix expressions needed for deployment together with a small shell script are stored in the directory &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;deployment/&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pkgs.nix&lt;/code&gt;: Expression pinning a specific version of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nixpkgs&lt;/code&gt; for reproducibility of builds.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;system.nix&lt;/code&gt;: A complete NixOS system configuration including:
    &lt;ul&gt;
      &lt;li&gt;a systemd configuration for running the backend application&lt;/li&gt;
      &lt;li&gt;an nginx configuration for exposing the frontend and the backend via HTTPS using Let’s Encrypt certificates&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;deploy.nix&lt;/code&gt;: Wrapper for the system configuration using the pinned version of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pkgs.nix&lt;/code&gt;. This expression can be used for building complete system configurations, which can be deployed to a remote server.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In addition the following Nix expressions are expected by this deployment setup:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dns.nix&lt;/code&gt;: Containing the DNS entries for the backend and the frontend application. For example:&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-nix highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;frontend&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;app.example&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;backend&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;api.example&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;network.nix&lt;/code&gt;: The NixOS network configuration of the application server. For example&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-nix highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;hostName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;dev&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;interfaces&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;ens3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ipv4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;addresses&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;address&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;a.b.c.d&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;prefixLength&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;28&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;ens9&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ipv4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;addresses&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;address&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;192.168.122.3&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;prefixLength&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;24&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;defaultGateway&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;a.b.c.d&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;nameservers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;8.8.8.8&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;firewall&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;allowedTCPPorts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;22&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;443&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;extraHosts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;    192.168.122.2 db&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;  ''&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Of course, the public IP address of the application server and the default gateway need to be filled in here. This configures two network interfaces, one public interface and one internal interface for talking to the database server (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;db&lt;/code&gt;).&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssh.nix&lt;/code&gt;: List of public SSH keys which can be used for logging into the application server:&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-nix highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;ssh-rsa ...&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Having this in place the actual deployment procedure is straight-forward and described in the shell script &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;deploy.sh&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$# &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-ne&lt;/span&gt; 1 &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
    &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Usage: &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$0&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; &amp;lt;remote ssh&amp;gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&amp;amp;2
    &lt;span class=&quot;nb&quot;&gt;exit &lt;/span&gt;1
&lt;span class=&quot;k&quot;&gt;fi

&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;REMOTE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;**** Deploying to &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; ****&quot;&lt;/span&gt;

nix-build &lt;span class=&quot;nt&quot;&gt;--attr&lt;/span&gt; system deploy.nix
&lt;span class=&quot;nv&quot;&gt;artifact&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;readlink &lt;/span&gt;result&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;
nix-copy-closure &lt;span class=&quot;nv&quot;&gt;$REMOTE&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$artifact&lt;/span&gt;
ssh &lt;span class=&quot;nv&quot;&gt;$REMOTE&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;artifact&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/bin/switch-to-configuration&quot;&lt;/span&gt; switch
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As can be seen, we build the system configuration from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;deploy.nix&lt;/code&gt; (using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nix-build --attr system&lt;/code&gt;), then we transfer the closure of the built artifact to the remote system and finally activate it. The shell script expects a remote ssh login as parameter, e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root@app.example&lt;/code&gt;. Credits to Gabriel Gonzales, as this procedure is heavily inspired by his post &lt;a href=&quot;http://www.haskellforall.com/2018/08/nixos-in-production.html&quot;&gt;NixOS in production&lt;/a&gt;.&lt;/p&gt;</content><author><name>Moritz Clasmeier</name></author><summary type="html">In the following post I describe how a simple Haskell web application built on top of Reflex FRP can be deployed to a remote NixOS server. If a remote NixOS server is available using it for deployment can be cheaper alternative to commercial cloud providers in case the features of those (e.g. scaling, hosted services, availability guarantees, etc.) are not strictly required.</summary></entry><entry><title type="html">Example: Conduit Streaming with Servant</title><link href="/2017/05/25/servant-streaming/" rel="alternate" type="text/html" title="Example: Conduit Streaming with Servant" /><published>2017-05-25T00:00:00+00:00</published><updated>2017-05-25T00:00:00+00:00</updated><id>/2017/05/25/servant-streaming</id><content type="html" xml:base="/2017/05/25/servant-streaming/">&lt;p&gt;&lt;a href=&quot;http://haskell-servant.readthedocs.io/en/stable/&quot;&gt;Servant&lt;/a&gt; is an awesome set of Haskell packages for Web development. Under the hood the Servant server uses &lt;a href=&quot;http://www.yesodweb.com/book/web-application-interface&quot;&gt;WAI&lt;/a&gt; and Warp. Forunately, the package &lt;a href=&quot;https://www.stackage.org/lts-8.15/package/wai-conduit-3.0.0.3&quot;&gt;wai-conduit&lt;/a&gt; provides support for creating HTTP responses from Conduit sources, which also allow for streaming responses from within a Servant server.&lt;/p&gt;

&lt;p&gt;Edsko de Vries has described the basic mechanism for doing this in a &lt;a href=&quot;https://github.com/haskell-servant/servant/issues/271#issuecomment-258079285&quot;&gt;Github comment&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This post describes this in more detail, giving a complete example (which can be cloned from its repository).&lt;/p&gt;

&lt;p&gt;Let us start! The server API type for a trivial non-streaming example looks like this:&lt;/p&gt;

&lt;div class=&quot;language-haskell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kr&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;ServiceAPI&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;one&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Get&lt;/span&gt; &lt;span class=&quot;sc&quot;&gt;'[&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;J&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;SON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;A handler implementing this endpoint is expected to return a value of type Int and Servant takes care of serializing this value before sending it to the client. An implementation for this API can look like this:&lt;/p&gt;

&lt;div class=&quot;language-haskell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;serveAPI&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Server&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;ServiceAPI&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;serveAPI&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;serveOne&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;serveOne&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Handler&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;serveOne&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, imagine we want to implement an endpoint &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/ones&lt;/code&gt;, which streams infinitely many ones. Say we would like to use Conduit, then a reasonable handler type for the endpoint &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/ones&lt;/code&gt; would look like this:&lt;/p&gt;

&lt;div class=&quot;language-haskell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;serveOnes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Handler&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Source&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;ResourceT&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;IO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Flush&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;ByteString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note: See the Conduit documentation for information on the Flush type.&lt;/p&gt;

&lt;p&gt;Given the above type, an implementation for serveOnes could look as follows:&lt;/p&gt;

&lt;div class=&quot;language-haskell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;serveOnes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;go&lt;/span&gt;
  &lt;span class=&quot;kr&quot;&gt;where&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;do&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Chunk&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Flush&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;go&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, in order to be able to use this handler for implementing a Servant API, we need to extend Servant’s Web API DSL. Say we would like to extend the above API with a streaming endpoint as follows:&lt;/p&gt;

&lt;div class=&quot;language-haskell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kr&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;ServiceAPI&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
   &lt;span class=&quot;s&quot;&gt;&quot;one&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Get&lt;/span&gt; &lt;span class=&quot;sc&quot;&gt;'[&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;J&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;SON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;
   &lt;span class=&quot;o&quot;&gt;:&amp;lt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;ones&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;GetStream&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;ByteString&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We can begin by definin a new type&lt;/p&gt;

&lt;div class=&quot;language-haskell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kr&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;GetStream&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In order to be able to use GetStream for defining Servant endpoints, we need to implement a HasServer instance for it. Edsko has demonstrated a basic class implementation in his comment on Github. I would like to make this a bit more configurable by defining a new type class Streamable:&lt;/p&gt;

&lt;div class=&quot;language-haskell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kr&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Streamable&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;where&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;streamableToBuilder&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Builder&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;streamableCT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Maybe&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;MediaType&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;streamableCT&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Nothing&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;streamableDelimiter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Maybe&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Builder&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;streamableDelimiter&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Nothing&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The method streamableToBuilder is obviously the most important method here as it allows us to convert a value of the type implementing this class into a ByteString Builder. The method streamableCT can be used for defining the response content type while streamableDelimiter can be used for defining a Builder delimiter which will be inserted in the response stream whenever the handler produces a Flush value. While we are at it, let us implement the following helper function:&lt;/p&gt;

&lt;div class=&quot;language-haskell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;toBuilderDelimited&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;forall&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Streamable&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Flush&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Flush&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This function will take care of inserting delimiters on Flush values. Implementing is is straight-forward:&lt;/p&gt;

&lt;div class=&quot;language-haskell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;toBuilderDelimited&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Chunk&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Chunk&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;streamableToBuilder&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;toBuilderDelimited&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Flush&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;streamableDelimiter&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;of&lt;/span&gt;
                             &lt;span class=&quot;kt&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;delim&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Chunk&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;delim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Flush&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
                             &lt;span class=&quot;kt&quot;&gt;Nothing&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Flush&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Having this in place, we can now implement HasServer for GetStream a:&lt;/p&gt;

&lt;div class=&quot;language-haskell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kr&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Streamable&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;HasServer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;GetStream&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ctxt&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;where&lt;/span&gt;
  &lt;span class=&quot;kr&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;ServerT&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;GetStream&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Source&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;ResourceT&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;IO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Flush&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;route&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_ctxt&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sub&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;leafRouter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;env&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;req&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;bracket&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;createInternalState&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;closeInternalState&lt;/span&gt;
              &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;runAction&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sub&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;env&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;req&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mkResponse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;kr&quot;&gt;where&lt;/span&gt;

      &lt;span class=&quot;n&quot;&gt;mkResponse&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;InternalState&lt;/span&gt;
                 &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Source&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;ResourceT&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;IO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Flush&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                 &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;RouteResult&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Response&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;mkResponse&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;st&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;Route&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;responseSource&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ok200&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.|&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;toBuilderDelimited&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.|&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;transPipe&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(`&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;runInternalState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;`&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;st&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

      &lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;ResponseHeaders&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
        &lt;span class=&quot;kr&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;maybeMediaTypeBS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Media&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;renderHeader&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;streamableCT&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Proxy&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;kr&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;maybeToList&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Content-Type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;maybeMediaTypeBS&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The function mkResponse is responsible for converting a Conduit source into a HTTP Response. It uses the previously defined helper function toBuilderDelimited and responseSource from the wai-conduit package. The function headers takes care of producing the desired Content-Type header.&lt;/p&gt;

&lt;p&gt;So far we don’t have any instances for Streamable. A naive implementation for ByteString might look like this:&lt;/p&gt;

&lt;div class=&quot;language-haskell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kr&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Streamable&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;ByteString&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;where&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;streamableToBuilder&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lazyByteString&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;ByteString&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Lazy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fromStrict&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here we convert a (strict) ByteString to a ByteString Builder without setting any content or delimiter.&lt;/p&gt;

&lt;p&gt;For a different use case one might want to stream newline-delimited JSON values using a content type of application/x-json-stream. The Streamable instance implementing this would be&lt;/p&gt;

&lt;div class=&quot;language-haskell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kr&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Streamable&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Value&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;where&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;streamableToBuilder&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lazyByteString&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;encodingToLazyByteString&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;toEncoding&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;streamableCT&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;application&quot;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Media&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.//&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;x-json-stream&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;streamableDelimiter&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lazyByteString&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Given this instance, we can extend our service API by writing&lt;/p&gt;

&lt;div class=&quot;language-haskell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kr&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;ServiceAPI&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;one&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Get&lt;/span&gt; &lt;span class=&quot;sc&quot;&gt;'[&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;J&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;SON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;
   &lt;span class=&quot;o&quot;&gt;:&amp;lt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;ones&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;GetStream&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;ByteString&lt;/span&gt;
   &lt;span class=&quot;o&quot;&gt;:&amp;lt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;hello&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;GetStream&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Value&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and implement a handler for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/hello&lt;/code&gt; endpoint as follows:&lt;/p&gt;

&lt;div class=&quot;language-haskell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;serveHello&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Handler&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Source&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;ResourceT&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;IO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Flush&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;serveHello&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;go&lt;/span&gt;
  &lt;span class=&quot;kr&quot;&gt;where&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;do&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Chunk&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Array&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Vector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;replicate&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;hello&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))))&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Flush&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;go&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This produces a stream of newline-delimited JSON arrays each containing 10 strings. That’s it for now, happy streaming!&lt;/p&gt;</content><author><name>Moritz Clasmeier</name></author><summary type="html">Servant is an awesome set of Haskell packages for Web development. Under the hood the Servant server uses WAI and Warp. Forunately, the package wai-conduit provides support for creating HTTP responses from Conduit sources, which also allow for streaming responses from within a Servant server.</summary></entry><entry><title type="html">PureScript Binding for Pebble</title><link href="/2016/05/28/fpebble/" rel="alternate" type="text/html" title="PureScript Binding for Pebble" /><published>2016-05-28T00:00:00+00:00</published><updated>2016-05-28T00:00:00+00:00</updated><id>/2016/05/28/fpebble</id><content type="html" xml:base="/2016/05/28/fpebble/">&lt;p&gt;I hacked together a very rudimentary PureScript binding for the &lt;a href=&quot;https://pebble.github.io/pebblejs/&quot;&gt;PebbleJS&lt;/a&gt; API, which allows for the writing of Pebble applications using Javascript.&lt;/p&gt;

&lt;p&gt;The project is named FPebble and its repository can be found on &lt;a href=&quot;https://github.com/mtesseract/FPebble&quot;&gt;Github&lt;/a&gt;..&lt;/p&gt;

&lt;p&gt;To get an impression of how a simple Pebble application can look like using PureScript, have a look at the &lt;a href=&quot;https://github.com/mtesseract/FPebble/blob/master/src/PureScript/src/Main.purs&quot;&gt;demo application&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/images/FPebble.png&quot;&gt;&lt;img src=&quot;/images/FPebble.png&quot; class=&quot;center&quot; width=&quot;30%&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</content><author><name>Moritz Clasmeier</name></author><summary type="html">I hacked together a very rudimentary PureScript binding for the PebbleJS API, which allows for the writing of Pebble applications using Javascript.</summary></entry></feed>