Singpolyma

Technical Blog

Archive for the "Tech" Category

UX Stability

Posted on

When I help friends and family with technical issues, or listen to them complain generally about their tech issues, one big theme comes up often: the upgrade treadmill. I don’t just mean that they complain that they have to always buy a new computer (though this is certainly an issue), but when they get a new computer they don’t know how it works. Every time an update for any piece of software installs, they have to learn their system all over again. And they feel like they didn’t really have a great handle on it to begin with.

This, I believe, actually leads to users being less willing to learn in the first place, since they (often rightly) believe that any knowledge they gain will be obliterated by changes to their User eXperience in short order. Software systems are, in this way, very user-hostile.

One way to solve this problem might be to simply not install updates, but this leads to a whole host of issues. The first one technical people will talk about is that not installing updates means your computer is even more full of security holes than usual. Enterprise-focused solutions involve so-called “Long Term Support”, where security fixes are backported to older versions of software for some support window. This can help in the short-term, but faces its own dilemma: if the support term is too short, then users are still upgrading fairly often, and the longer you make the support term, the longer users have to wait for new features and (sometimes) bugfixes.

But wait! Don’t the users not want new features? Isn’t this a good thing? Wrong. Users want updates what they don’t want is change. When Firefox gains the ability to play a new kind of video, users want that, because they want the webpages they visit to work. When Libreoffice improves support for a popular file format, users want that, because they want to be able to open files they get sent. Even straight-up new functionality may be welcome in certain cases. So long as the new feature does not invalidate the user’s existing workflow. This is the key. A user that can trust their workflow will keep working (and you won’t replace all their menus with new menus, or worse, non-menus) is (I think) more willing to learn to begin with. Certainly more happy in the long run.

So keeping a system stable in the way that, say, Debian or RHEL or Ubuntu LTS do is a very useful start, but it’s not the whole story. We need a system that stays the same (or at least, whose core components change very little) while also receiving bug fixes and new functionality. Backporting, from time to time, bugfixes and new features in a way that preserves the user’s experience. For what support window? This is a big task, and starting with shorter timeframes may be needed, but ultimately? Forever. Or for the life of the users at least. A user should never be put into a position where they are forced to re-learn their system just to keep using it. Computers are tools that many people find essential to their daily lives, and there is a duty to provide them with systems that keep working, not just technically, but for the user.

Obviously, we cannot achieve this with proprietary software, so software freedom is an important part of this. And also, we cannot easily achieve it with any application that delivers the UI remotely (such as a “web app”), so native clients for popular web applications and similar technology may be needed in order to be able to provide this kind of stability. This is not a small task that we can accomplish overnight, but I believe it is part of the essential solution to the problems our society faces with their daily computing needs.

How About That Tablet?

Posted on

Last year I announced that I would spend a good chunk of 2015 working on the creation of a freedom-respecting tablet computer. How did that go?

Well, first, unsurprisingly, I ran into the massive wall of companies-will-not-talk-to-you. I only managed to get a tiny number of PCAP vendors to even begin discussions with me, and even fewer were willing to sell me prototyping gear. I spent too much on some stuff that ultimately wouldn’t work well (too bulky/heavy) but that I’m still tinkering with anyway. However, back to where I started, I eventually got in touch with people at Chalkboard Electronics about doing custom/bulk orders. They will do very small (MoQ 100) custom board spins (for simple changes like “please use LVDS directly instead of a built-in HDMI converter”). I have tested their generally-available hardware with my Novena and it works quite well.

The software situation is overall much better than I expected. Many GNOME applications support multitouch gestures already, and there are several on-screen keyboards that work reasonably well. Auto-rotation of the display on the Novena is a pretty simple shell-script. Though getting a browser that works well might be some more effort.

The battery situation turned out to be more complex than I had imagined. There is no (that I have found) good, free-design USB battery charging + passthrough solution. Maxim proved to be pretty willing to sell an eval kit for their MAX8895 series if I want to try building a solution based on that. The Novena and PiTop both use a higher-voltage barrel-jack charger, which could work for a tablet but is not ideal. The PiTop ended up going with a “smart battery”, so there is not reusable part to try there. I have an extra Novena battery board that I hope to experiment with this year and get it to power alternate SBCs.

I also got distracted this year, not least of all by my Free Culture project which resulted in a (very) small-run print of the Big Buck Bunny Board Book, of which I gave one to my niece for Christmas.

Also making good-looking progress is LKCL’s projects at rhombus-tech. While he has some strange ideas, he seems very close to executing on the laptop design and has been quite willing to share information about his suppliers, etc.

So where next? Am I going to really build a tablet for sale? Probably not any time soon. But I’ve learned a lot, and will keep tinkering with the hardware that I have. Maybe I’ll get a battery charging solution working this year, that would be nice.

Electronic Device Freedom

Posted on

The software freedom movement was born in the 1980s out of a need to champion certain
essential freedoms for computer users:

  • The freedom to run the program as you wish, for any purpose
  • The freedom to study how the program works, and change it so it does your computing as you wish
  • The freedom to redistribute copies so you can help your neighbour
  • The freedom to distribute copies of your modified versions to others

These freedoms cover the basic necessities for computer users, but over the years computers have changed, showing us latent ambiguities in this definition. What is “the program”? What is “computing”?

Papering over a binary blob

When the software freedom movement started, a lot of things about computing were simpler. Instructions executing on a CPU would send and receive signals to and from various attached buses in order to initialize and control all of the system’s peripherals. Operating systems needed very specific device drivers for each peripheral that existed on the planet. So “software” was simply everything that contained instructions for the CPU and “computing” was simply the use of “a computer”, which probably seemed pretty clearly defined at the time.

As peripherals grew in number and complexity, there was an increasing need to run some of the instructions that governed their operation on microprocessors other than the CPU. This was done both for performance (so the CPU would not need to be involved for every single bit of WiFi data your antenna sees) and for standardization (so that all storage drives could speak the same language to the host computer). This leads to the question: are these instructions “software”? More specifically, do users of the computer need to have the same freedoms with these instructions as they do with other software in order to have freedom in their computing?

The Free Software Foundation drew the line for “software” at executable instructions that could be altered in a device by the user. The idea is that if the user cannot update the instructions, then they cannot exercise their freedoms even if they were provided them in some theoretical way. These instructions, though made of the same “stuff” as software, are considered a part of the hardware. Of course, this just adds a new question: what does it mean to say “the user can update the instructions”? If they have to desolder and replace a chip, but said replacement chip can be easily had, is that enough?

Discussions around these issues often get lost in the weeds of trying to define the words used in the definition of software freedom published by the FSF. But if the real question is freedom, then the answer lies not in the words, but in the purpose of the words. If “running free software on your computer means that its operation is under your control,” then traditional software freedom is no longer sufficient. Let us examine each freedom in turn.

The freedom to use the device as you wish, for any purpose

Back to an earlier question: what is “computing”? Well, given the context of the software freedom movement, I would argue that “computing” is any context in which the same components as “computers” are used. That is, digital electronics and instructions that command those electronics.

This means that using your TV is a form of “computing”. As is using your mobile phone, your printer, your car, your climate-control system, your health-monitoring band, or your treadmill. These things may not all be what they thought of in the 1980s as “computers”, and they may not even be what we normally think of today as “computers”, but they have the ability to provide or restrict freedom in the same ways as computers, and so I think the same freedoms should be considered in this broad context.

And so, to change the wording slightly of the FSF’s freedom 0: users need the freedom to use their devices as they wish, for any purpose. The fundamental need for this freedom derives from our ideas as a society about personal property. If you own a device, you should be allowed to use that device as you wish, and not only as the creator imagined. You should be free to use your old phone for anything from holding down papers to using its battery to power some new contraption. You should be free to give your old eBook reader to a friend. You should be free to plug your music player into a device that makes it play louder. You should be free to use your DVD player to play home movies and not just Hollywood movies.

The most common violation of this freedom that we fight today is technological protection measures (TPMs), also called digital restrictions, digital locks, digital handcuffs, or DRM. The software freedom movement has been part of the fight against TPMs since they first became a major issue. Your devices may simply refuse to open the movies, music, apps, or books you load onto them. Laws in many countries of the world, intended to protect a few interest groups, make it a criminal offence even to modify your DVD player so it can play some DVDs, your eBook reader to read some eBooks, your phone to run some apps, or your television or digital receiver to have a new video output. This is just one way in which your freedom to use your device as you wish is violated.

The freedom to study how the device works, and change it so it does your computing as you wish

The freedom to change your device is partly about the freedom to use it as you wish. You should be free to use your devices in both ways the creator imagined, and also in new ways. However, if no one is allowed to understand how the device works, or produce ideas for such novel uses, then your freedom to use your device will be limited to uses that are in line with what can be understood about it. What good is being allowed to play home movies on your DVD player if no one knows how to put your home movies onto a DVD?

The smallest part of this freedom is also an expression of your personal property rights. You should be free to open up your devices and look inside. You should be free to send various signals to your device in an attempt to understand how it responds. You should be free to attach new devices to the insides of your device in order to study whatever properties of those insides you wish to study.

So far, these freedoms do not mean that it is the job of the creator to go out of their way to make such things easy. Just as the freedom of the press does not protect reporters from ridicule or war correspondents from bombs, so too the freedom of device modification does not require that update mechanisms be provided. But if you, someone you know, or a new startup company can figure out how to put your device to some new use, they must have the freedom to do so, without fear of successful lawsuit or criminal prosecution.

However, we must go further than that. You need the freedom to study how your devices work, not just to study how they are put together. The fundamental need for this freedom derives from the same source as competition law and consumer protection. Even if you do not intend to study how your device works, you must be free to do so because you need others to be free to do so. If there is a dangerous problem with your device, you should be able to find out. If new devices are to be made, students must be free to study devices that exist.

Imagine mechanics and engineers being trained without being told how existing engines work. Imagine pilots and aerospace engineers being trained without being told how planes are able to fly. Just looking at an airplane is not enough: students must be told how it works. Yet with many devices we use every day, if a student asks how some features of the device work, they might only be told “we don’t know and it is a criminal activity for us to try and find out”.

In order to know how a device works you must know what components are in it and what they do. Many components are not clearly labelled, or their labels come off with time, so it is important to have access to documentation detailing which components were used, and where to find them in the device, or study of these parts of the device may be impossible. Documentation must also exist for each component, detailing what it does. Common components, such as resistors or transistors, are readily documented in general knowledge, and so simply saying “this is a 5 ohm resistor” may be sufficient. Integrated circuits may need a bit more explanation, such as “this flash memory can be communicated with according to such-and-such a protocol”. For circuits that can be reprogrammed, such as microprocessors, you need access to the source code that creates the instructions running on those circuits. For circuits composed of multiple devices (such as a System on Chip) you need to know what devices are present, and how to communicate with each one.

Note that even here there are levels of depth. If I know that a device uses a particular system on chip, what capabilities that system on chip has, and have the source form of the instructions that run on that system on chip, then I can understand how my device works. I may not understand how another device that I own (namely, the system on chip itself) works, but I know how the device it is embedded within works. And so we have devices within devices, possibly further nested than this. Really we do need the freedom to study how all our devices work. However, if our freedom is restricted on one device that might not necessarily restrict our freedoms with respect to devices made out of that device.

Some creators violate these rights by intentionally obscuring what components they have used. Sometimes laws exist to prevent anyone from studying some components directly (for example, in many countries it would be criminal activity to discover how a DVD player’s TPMs work, even though we already know). However, the largest way in which these rights are violated is by omission: creators simply do not tell us what components they have used or what instructions they have given to those components, and so we have no effective way of finding out how the device works at all.

The freedom to tell others how your device works so you can help your neighbour

Not everyone has the time or resources to study how their devices work. If everyone had the freedom to study in this way, but could not share what they had learned, then what have we gained? And so it is important that you be free to share what you have learned with others, and to tell others what instructions are running on the microprocessor or what the use of some particular combination of components is.

The most common way in which this freedom is violated is by the use of copyright law or non-disclosure agreements to restrict the redistribution of source code, specifications, or schematics.

The freedom to create new devices based on your existing devices, and to distribute these new devices

I once asked Richard Stallman, a key leader of the software freedom movement, why he doesn’t propose that freedom should be extended to the hardware level in our devices. He replied that he doesn’t need that freedom because he doesn’t have a fabrication line. This line of reasoning is, I expect, also what lead the Free Software Foundation to classify freedom for microprocessor instructions that a user cannot update as non-essential. The idea is, if you cannot make the change, then what good is your freedom to make that change doing you?

I would suggest that the change can always be made, but you may not be able to make it alone. It is getting easier and easier for smaller groups to get electronics of various kinds fabricated. I may not be able to update the firmware on my keyboard, but I could (if someone makes one, which they should have the freedom to do) order a replacement controller and have someone install it for me. I may not be able to update the software on my car’s multimedia system, but I could pay someone to install a new multimedia system in my car. I may not be able to add new instructions to my car’s fuel injection system, but I can install an aftermarket controller in an attempt to boost my fuel efficiency.

So it is that you need not only the freedom to study existing devices, so that you know how they work, but the freedom to make new devices, so that everyone can benefit. The key ways in which this freedom is violated today are both copyright and patent laws, preventing new devices from being made that reuse either parts of the software or techniques of previous devices.

Limitations on Freedom

I have up to this point talked about freedom as an absolute, but of course it is not. In the same way that your freedom of speech does not prevent libel lawsuits or protect your hate speech, so should your electronic freedom not be without limit. While you need to be free to use your device as you wish, if you use it to criminal ends you may still be prosecuted as a criminal. When you are granted the freedom to study or alter your device, it must be without specific restriction, but other restrictions may reasonably be placed on you by lawmakers according to the governance of your society.

Partial freedom

We do not yet live in a world where every computing-related device one might need to use, or every computing-related goal one might need to acheive, can be achieved in perfect freedom. That is, of course, our goal, and an important part of reaching that goal is to make use wherever possible of the freedom that we do have. However, sometimes one must make a very difficult choice.

If you value freedom, you may desire a laptop whose CPU you can study and modify. However, no effective laptop of this nature currently exists. So there is a choice: use a laptop that disrespects some of your essential freedoms, or do not use a laptop at all. However, the choice is hardly a binary one. You may chose a laptop which can be operated entirely using instructions to the CPU and peripherals that can be studied. This is certainly a huge improvement over a laptop where nothing can be studied, even if it is not ideal!

Even the GNU project, the flagship software freedom project of the FreeSoftware Foundation, was initially developed using software that did notprovide the members of the GNU project with freedom. Why? Becausefreedom-respecting tools did not yet exist — they were in the midst of creating them!

You will never have freedom if you wait for the perfect ideal before you begin to prefer tools that respect your freedom. However, you will also never have freedom if you do not carefully consider the implications of devices and programs you choose. The question that is always before you is: are you compromising your freedom out of necessity, or because of a lack of knowledge of motivation? Take your own freedom, and the freedom of your neighbour, seriously.

Innovation

We will never achieve the freedom we desire if we content ourselves with fighting for the freedom of devices we already know about. This is the sort of strategy that led to freedom existing only for desktop computers, and then for desktops and laptops, and losing (without even knowing it was happening) the battle for keyboards, mice, touchscreens, cellular data modems, and so many other peripherals. If we only work to free what exists, then we will miss out on every new thing that might exist, and many users will be tempted away from freedom by new devices.

So what am I saying we must anticipate every possible new device? Should we have anticipated projected capacitive touch technology and the Thalmic Myo and the health monitoring arm-bands and smart-watches and every other thing? Of course not, that would be impossible. Rather, we should: convince more people to care about their freedom enough so that new innovators care to think to give it to them, and we should work on new innovations ourselves, and not be content to simply copy what we see around us in our work for freedom.

What am I going to do about it?

I have been a software freedom advocate for some time now, and have worked on such issues as freedom for interactive websites and freedom in the social networking space. The work is not yet done in these areas, though great progress has been made. I, however, plan to shift my focus in 2015 down a few layers to the devices we use themselves. I have already been supporting amazing devices that greatly (if not completely) respect users’ freedom, such as:

  • Novena, a motherboard, battery control board, and laptop for hardware research, prototyping, and creation
  • Gluglug Laptops, refurbished laptops that respect your freedom in every aspect of the software
  • USB Armory, a freedom-respecting USB-powered computer for security applications
  • ZaReason Computers — most of their devices respect user freedom in all instruction executing on the CPU

And there are other devices which might be of interest as well, including the GCW Zero, a handheld gaming console, and FSF endorsed devices.

On the new work front, I am tackling the tablet and netbook space. Hardly the most innovative space, I agree, but this will give me experience with whole-device creation as well as touch-panel technology that I think will be useful in the creation of many possible future devices. My goals for the near future are the following:

  1. Source and install a PCAP panel for my Novena when it arrives, and have this working as a pseudo-tablet by sometime in the spring
  2. By the end of 2015, have a prototype tablet built out of a readily-available single-board computer that anyone with access to a makerspace could replicate
  3. Do the work to turn this prototype into an acceptable tablet form-factor

After this point, a tablet that respects user freedom in every instruction executing on a microprocessor (except the PCAP controller) should be possible. So all that will remain for the tablet itself is to create a liberated PCAP controller that will work with easily-obtained microprocessors. This may involve reverse-engineering touch panels to some degree, and will definitely involve complex finger-tracking algorithm development for multitouch.

This is not a short-term project, and I’m not going to quit my day job, so it is likely that needs (and my abilities) will change eventually, resulting in new directions, but for the next chunk of time, this will be my priority.

What are you going to do about it?

You, too, can do your part for freedom. If you are a software developer (like me) you can create new innovative software that respects freedom or contribute to existing software freedom projects. If you are a hardware hacker, you too can work on devices where there is need. If you have money you can help fund important projects and organizations. If you have a small community with software or device-related needs, you can tell people about those needs. Freedom means the freedom to have your needs met (though you may need to find someone with the skills to make the necessary improvements), and not be forced to wait until some big company decides there is a market for the features you desire. Get out there and use the freedom-respecting technology that exists, figure out what is wrong with it, talk about it, tell people in the community where things can be improved. We have come a long way since the 1980s, but there is so much more to do, and everyone can be a part of it.

Why is That Value False?

Posted on

This post is a response to Boolean Externalities, so you should probably read that first.

The core of this problem is a lack of combinators. In order to propogate the reason why something is falsy, you need to add a lot of logic to each method, which noises up the code considerably.

So we start with a pseudo-falsy base class for all our possible “reasons”:

class WhyFalsy
	# This is so you can convert to bool with !!
	def !@
		true
	end

	def blank?
		true
	end
end

Now we can make objects that represent particular reasons, like:

class NoConfirmedAt < WhyFalsy; end

And use them in conditionals with only a little syntax pain:

!!NoConfirmedAt.new ? "confirmed at" : "not"

Now that we have these objects, we can create methods that let us combine them without throwing away the information we care about:

class WhyFalsy
	def or
		yield
	end

	def and
		self
	end
end

class Object
	def or
		self
	end

	def and
		yield
	end
end

class FalseClass
	def or
		yield
	end

	def and
		self
	end
end

class NilClass
	def or
		yield
	end

	def and
		self
	end
end

The normal && and || operators cannot be overloaded, so we define our own very similar methods, which allow us to write code like this:

def fully_authenticated?
	authenticated_accounts?.and { verified_email? }
end

Where any pseudo-falsy reason value we bubble up will be treated the same as the actual false or nil, and any other value will be treated truthily, same as before.

What if we want to wrap the result of some existing API (or DB column) in a reason? That’s a pretty easy smart constructor:

class WhyFalsy
	def self.wrap(x)
		# The !! makes fake-falsy values (like us) work
		!!x ? x : self.new
	end
end

Now we can easily wrap any existing API:

NotFree.wrap(free?)

Developers are lazy, and especially if they’re just using this in debugging they just want to use English text, like so:

class WhyFalsy
	attr_reader :msg

	def initialize(msg=nil)
		@msg = msg
	end
end

And while all these ways to know why something is falsy are nice, it would be even nicer if we could know *where* the falsy value came from:

class WhyFalsy
	attr_reader :msg, :backtrace

	def initialize(msg=nil)
		@msg = msg

		# Hack to get a backtrace
		begin
			raise
		rescue Exception
			@backtrace = $!.backtrace
			@backtrace.shift # Remove the reference to initialize
		end
	end
end

And there you have it, a complete, workable solution for propogating the information we care about all the way up to our call site.

Haskellers might recognize that this is basically a very-Rubyified encoding of the following:

import Control.Applicative
import Data.Monoid

instance (Monoid r) => (Either r) where
	empty = Left empty
	Left _ <|> x = x
	     x <|> _  = x

wrap True _    = Right ()
wrap False msg = Left msg

fully_authenticated = authenticated_accounts *> verified_email
available_to_user = free <|> (current_subscriber user)

The full code from this post is available as a gist.

Making A Website With Haskell

Posted on

This is a guide to building simple webapps using Haskell (modelled after this article on a different framework). We will use:

  • WAI (Web Application Interface, and various utilty packages) for the backend
  • mustache2hs for templating
  • sqlite-simple for database access

Getting set up

There is a very useful utility for building Haskell called Cabal, which will allow you to track which versions of which dependencies you are using, and will tell you if they are not properly installed, etc. Create a project.cabal config file, like so:

name:            project
version:         0.1.0
cabal-version:   >= 1.8
category:        Web
copyright:       © 2013 Your Name
author:          Your Name <youremail@example.com>
maintainer:      Your Name <youremail@example.com>
stability:       experimental
synopsis:        My awesome todo-list app
homepage:        http://github.com/yourName/repoName
build-type:      Simple
description:
        A longer description of my awesome app

executable Main
        main-is: Main.hs

        build-depends:
                base == 4.*,
                http-types,
                wai,
                wai-util,
                wai-dispatch,
                yesod-routes,
                warp,
                text,
                path-pieces

source-repository head
        type:     git
        location: git://github.com/yourName/repoName.git

cabal configure will check that you have everything installed cabal build will build your project.

You may want to set up a Makefile, like so:

GHCFLAGS=-Wall -fno-warn-name-shadowing -XHaskell98 -O2

dist/build/project/Main: project.cabal dist/setup-config Main.hs
    cabal build --ghc-options="$(GHCFLAGS)"

dist/setup-config: project.cabal
    cabal configure

.PHONY: clean

clean:
    find -name '*.o' -o -name '*.hi' | xargs $(RM)
    $(RM) -r dist dist-ghc

Hello World

Save this as Main.hs:

module Main (main) where

import Network.Wai.Handler.Warp (run)
import Network.HTTP.Types (ok200)
import Network.Wai.Util (string)

main = run 3000 (\_ -> string ok200 [] "Hello, World!")

Now make and run it:

cabal build
dist/build/bin/Main

Go to http://localhost:3000 and you should see your Haskell site!

Routing

Our previous app gave the same response to every request. We will use the routeGenerator utility to create fast, compiled routes from a simple syntax:

cabal install route-generator

Add the following rule to your Makefile:

Routes.hs: routes
    routeGenerator -r -m Application $< > $@

You will want a file named routes with your routing information in it.

The router supports any possible HTTP method:

GET / => homePage
POST / => postPost
PURCHASE / => buyTheThing

Where the names on the right-hand side are the names of functions in your Application.hs module.

You can also capture parameters:

GET /post/: => showPost

Here’s an example of an Application.hs with handlers for these routes:

module Application where

import Network.HTTP.Types (ok200, notFound404)
import Network.Wai (Application)
import Network.Wai.Util (string)

homePage :: Application
homePage _ = string ok200 [] "Hello, World!"

postPost _ = string ok200 [] "You posted!"

buyTheThing _ = string ok200 [] "Bought it!"

showPost arg _ = string ok200 [] arg

on404 _ = string notFound404 [] "Not found"

And run the whole thing, with the proper 404, like so:

module Main (main) where

import Network.Wai.Handler.Warp (run)
import Network.Wai.Dispatch (dispatch)
import Application
import Routes

main = run 3000 $ dispatch on404 routes

Headers

Get a header:

import Network.Wai.Util (bytestring)
import Data.String (fromString)
import Data.Maybe (fromMaybe)
import Data.Monoid (mempty)

homePage req = bytestring ok200 [] (fromMaybe mempty $ lookup (fromString "User-Agent") $ requestHeaders req)

Set a header:

import Network.Wai.Util (stringHeaders')
homePage _ = string ok200 (stringHeaders' [("Content-Type", "text/calendar")]) "Not a calendar ;)"

Content types

Respond with the appropriate content type:

import Network.Wai.Util (handleAcceptTypes, string, json)

homePage = handleAcceptTypes [
        ("text/plain", string ok200 [] "You asked for text, here it is.")
        ("application/json", json ok200 [] ["A JSON", "array"])
    ]

Templates

There are many good templating systems. My favourites are blaze-html and mustache2hs, because:

  1. They give you some type-checking of your templates at compile time.
  2. They are super fast.

To use mustache2hs, first install it:

cabal install mustache2hs

You will need a module to contain the records that you will render out in your template (Records.hs):

module Records where

data HomePageData = HomePageData {
        title :: String,
        username :: Maybe String
    }

And an actual template to render (homePageView.mustache):

<html>
    <head>
        <title>{{title}}</title>
    </head>
    <body>
        <h1>{{title}}</h1>

        {{#username}}
            Welcome, {{username}}!
        {{/username}}
    </body>
</html>

Set up your Makefile to generate the code:

MustacheTemplates.hs: Records.hs homePageView.mustache
    mustache2hs -m Records.hs homePageView.mustache HomePageData > $@

And actually render it out:

import Network.Wai.Util (stringHeaders', textBuilder)
import MustacheTemplates

htmlEscape :: String -> String
htmlEscape = concatMap escChar
    where
    escChar '&' = "&amp;"
    escChar '"' = "&quot;"
    escChar '<' = "&lt;"
    escChar '>' = "&gt;"
    escChar c   = [c]

homePage _ = textBuilder ok200
    (stringHeaders' [("Content-Type", "text/html; charset=utf-8")])
    (homePageView htmlEscape $ HomePageData "My Title" Nothing)

Logging Requests

If you want to see a log of all requests on standard out, you’ll need to change Main.hs to use a middleware:

import Network.Wai.Middleware.RequestLogger (logStdoutDev)

main = run 3000 $ logStdoutDev $ dispatch on404 routes

Serving Static Content

If you want to serve a directory of static content alongside your app, you can use a fallback mechanisms from the wai-app-static package:

import Network.Wai.Application.Static (staticApp, defaultWebAppSettings)
import Filesystem (getWorkingDirectory)

staticRoot = staticApp . defaultWebAppSettings

main = do
    cwd <- getWorkingDirectory
    run 3000 $ dispatch (staticRoot cwd) routes

Or alternately use the middleware from wai-middleware-static:

import Network.Wai.Middleware.Static (static)

main = run 3000 $ static $ dispatch on404 routes

Sessions

Some apps need a way to store data between requests using cookies. wai-session is a package that provides a generic way of doing this, and has existing backends for in-memory storage, encrypted cookies, and tokyocabinet. The wai-session-clientsession package contains the backend for encrypted cookies:

module Main where

import Data.Default (def)
import Data.Maybe (fromMaybe)
import Data.String (fromString)
import qualified Data.Vault as Vault

import Network.Wai
import Network.Wai.Util (string)
import Network.Wai.Handler.Warp (run)
import Network.HTTP.Types (ok200)
import Control.Monad.Trans.Resource (ResourceT)

import Web.ClientSession (getDefaultKey)
import Network.Wai.Session (withSession, Session)
import Network.Wai.Session.ClientSession (clientsessionStore)

app session env = do
    u <- sessionLookup "u"
    sessionInsert "u" (show $ pathInfo env)
    string ok200 [] $ fromMaybe "Nothing" u
    where
    Just (sessionLookup, sessionInsert) = Vault.lookup session (vault env)

main = do
    session <- Vault.newKey
    store <- fmap clientsessionStore getDefaultKey
    run 3000 $ withSession store (fromString "SESSION") def session $ app session

Databases

For database access, use postgresql-simple or sqlite-simple:

import Database.SQLite.Simple (open, close, query, Only(..))
import Database.SQLite.Simple.FromRow (FromRow(..))

data Post = Post {
        postTitle :: String,
        postBody :: String
    }

instance FromRow Post where
    fromRow = Post <$> field <*> field

showPost :: Int -> Application
showPost postId _ = do
    conn <- open "./production.sqlite3"
    [post] <- query conn "SELECT * FROM posts WHERE post_id = ?" (Only postId)
    string ok200 [] (postTitle post)
    close conn

Of course, you shouldn’t probably re-connect on every request. Change your Makefile to have the router pass an argument through:

Routes.hs: routes
    routeGenerator -r -n 1 -m Application $< > $@

And do the connection from Main.hs:

import Database.SQLite.Simple (open, close)

main = do
    conn <- open "./production.sqlite3"
    run 3000 $ dispatch on404 (routes conn)
    close conn

And then you can use the connection:

showPost :: Connection -> Int -> Application
showPost conn postId _ = do
    [post] <- query conn "SELECT * FROM posts WHERE post_id = ?" (Only postId)
    string ok200 [] (postTitle post)

Deploying to Heroku

Deploying to Heroku is easy with the heroku buildpack.

First, our hello world app needs to change slightly. Heroku tells us what port to run on with the PORT env variable:

module Main (main) where

import System.Environment (getEnv)
import Network.Wai.Handler.Warp (run)
import Network.HTTP.Types (ok200)
import Network.Wai.Util (string)

main = do
    port <- fmap read $ getEnv "PORT"
    run port $ string ok200 [] "Hello, World!"

Then add a Procfile in your root dir to tell Heroku how to start your app:

web: ./dist/build/project/Main

And add a Setup.hs to build your app:

import Distribution.Simple
main = defaultMain

Then, assuming your project is a git repo:

heroku create --stack=cedar --buildpack https://github.com/pufuwozu/heroku-buildpack-haskell.git
git push heroku master