<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
 <head>
  <title>Extending Asterisk with HAppS</title>
  <link type='text/css' rel='stylesheet' href='hscolour.css'>
 </head>
<body>
 <h1>Extending Asterisk with HAppS</h1>
  <p>I just glued two of my favorite technologies together, <a href="http://www.asterisk.org">Asterisk</a> (the opensource PBX/VoIP/etc system) and <a href="http://www.happs.org/">HAppS</a> (the Haskell Application Server framework).</p>

<p>If you have heard of HAppS, but never used it, you may have the impression that HAppS is a web development platform -- but that is not quite correct. HAppS is actually a collection of several different server components which can be combined together or used separately.</p>

<p>In this post, I will show how to build as simple FastAGI server on top of the HAppS-State component. We will not be using the web component (HAppS-Server), which is the part that provides HTTP, templating, cookies, etc. This post assumes no prior knowledge of HAppS or AGI.</p>

<h2>What You Will Need</h2>
<p>If you want to build this demo you will need:</p>
<ul>
<li>the latest version of HAppS-State and it's dependencies.
<li>Asterisk (I think any version later than 1.0 should work. I use 1.4.17 from Ubuntu Hardy)
<li>The <a href="http://hackage.haskell.org/cgi-bin/hackage-scripts/package/AGI">haskell AGI library</a>
</ul>

<h2>FastAGI</h2>
<p>The asterisk server can be extended by using the <a href="http://www.voip-info.org/wiki/index.php?page=Asterisk+AGI">Asterisk Gateway Interface (AGI)</a>. It provides the functionality you need to do stuff like <i>"Please enter your 16-digit account number."</i></p>

<p>An AGI script is a standalone program you write (in a language of your choice), which will be run by asterisk. Asterisk communications with your AGI script by writing to its stdin and reading from its stdout. The <a href="http://gundy.org/asterisk/agi.html">commands and responses</a> are human readable text.</p>

<p>Asterisk also has the option of communicating with your AGI script remotely via TCP instead of directly running a local program. This feature is known as FastAGI. The commands and responses are identical to normal AGI, the only differences are:</p>
<ul>
<li>The communication channel is setup via TCP instead of forking off a local process
<li>Some extra AGI variables are passed in by FastAGI
</ul>
<p>There is one additional import difference, which is more of a side-effect. When using AGI, a new process will be spawn for each call. When using FastAGI, a new TCP connection will be opened -- typically to a single, long running server process. So, with AGI you will need to worry about how to provide communication and synchronization between multiple processes, but with FastAGI, you can just use threads.</p>
<h2>HAppS-State</h2>
<p>The HAppS State component provides in-memory state with ACID guarantees. It uses write ahead logging and checkpointing to ensure the state can be restored from disk in the event of a power outage, and also provides multimaster replication. Unlike a traditional relational database, HAppS-State works directly with native, arbitrary Haskell data types. This means you don't have to figure out how to get your beautiful data structures wedged into a relational database just to get ACID guarantees.</p>
<h2>Example Application</h2>
<p>The remainder of the post is a simple hit-counter AGI application. You just call the phone number, and it tells you what caller number you are. I won't go into much detail about the HAppS State portion, since this post is supposed to show how to integrate AGI, not how to use HAppS State.</p>

> {-# LANGUAGE TemplateHaskell, UndecidableInstances, TypeFamilies, 
>  TypeSynonymInstances, FlexibleInstances, DeriveDataTypeable, 
>  MultiParamTypeClasses, TypeOperators, GeneralizedNewtypeDeriving #-}

> module Main where
>
> import Control.Concurrent
> import Control.Monad
> import Control.Monad.Reader
> import Control.Monad.State
> import Control.Monad.Trans
> import HAppS.Data
> import HAppS.State
> import Network
> import Network.AGI
> import System.Random
> import System.Posix.Unistd

 <p>The first thing we do is define the type we will use to store our
 persistant state. This is our database. The <code>deriveAll</code> is
 similar to <code>deriving (Eq, Ord, Read, Show, Num, Enum, Default,
 Data, Typeable)</code>. Since there is no way to extend the
 <code>deriving</code> we have to use template Haskell to add support
 for deriving <code>Default</code>.
 </p>

>
> $(deriveAll [''Eq,''Ord,''Read,''Show,''Num,''Enum,''Default]
>  [d|
>      newtype HitCounter = HitCounter { hits :: Integer }
>   |])


 <p><code>deriveSerialize</code> is the magic that allows HitCounter
 to be serialized to disk or replicated between servers.</p>

>
> $(deriveSerialize ''HitCounter)

 <p>The <code>Version</code> instance is used to support migrating the
 old data if modify the <code>HitCounter</code> data structure. That
 is a subject for a different tutorial.</p>

> instance Version HitCounter

 <p>Next we define a function which modifies the global state
 (<code>HitCounter</code>). This function while be run
 automatically. This means that there is no race condition between the
 <code>get</code> and the <code>put</code>. The <code>get</code> and
 <code>put</code> functions the ones found in
 <code>Control.Monad.State</code>.</p>

>
> -- |increment hit counter, and return new value
> incHits :: Update HitCounter Integer
> incHits = 
>     do hc <- fmap succ get
>        put hc
>        return (hits hc)

 <p>This is the magic which converts the <code>incHits</code> function
 into an atomic function for updating the global state.</p>

>
> $(mkMethods ''HitCounter
>    [ 'incHits
>    ])

 <p>Next we define our top-level component which uses the global state. A more complex application might use a bunch of independent components similar to HitCounter. This allows us to easily build things like session support, user accounts, etc, in third party reusable libraries. I believe it also makes atomic locks finer grained and makes it possible to support shards. </p>

>
> instance Component HitCounter where
>     type Dependencies HitCounter = End
>     initialValue = HitCounter 0

> entryPoint :: Proxy HitCounter
> entryPoint = Proxy

<p>The <code>main</code> function starts up the state engine, forks off the <code>fastAGI</code> server, waits for the server to receive a shutdown signal (for example, ^C), and then cleanly shuts down the state engine. The <code>fastAGI</code> function comes from the Haskell AGI library, and is in no way HAppS specific.</p>

>
> main :: IO ()
> main =
>     do control <- startSystemState entryPoint
>        tid <- forkIO $ fastAGI Nothing agiMain
>        putStrLn "running..."
>        waitForTermination
>        killThread tid
>        shutdownSystem control

<p>Here is our simple AGI application. It</p>
<ol>
 <li>answers the call
 <li>waits a second to give the caller time to finish setting up their end of the call
 <li>increments the hit counter
 <li>plays a pre-recorded file which says, "You are currently caller number"
 <li>says the caller number
 <li>plays a pre-recorded file which says "Goodbye."
 <li>hangs up
</ol>
 
 <p> The functions <code>answer</code>, <code>streamFile</code>,
 <code>sayNumber</code>, and <code>hangUp</code> come from the AGI
 library.</p>

 <p>The, <code>update IncHits</code> call is our database query. Note
 that we don't call the <code>incHits</code> function
 directly. Instead we call <code>update</code> and pass it the value
 <code>IncHits</code>. The <code>IncHits</code> type was created for
 us automatically by the call to <code>mkMethods</code> we made
 earlier.</p>

> 
> agiMain :: HostName -> PortNumber -> AGI ()
> agiMain hostname portNum =
>     do answer
>        liftIO $ sleep 1 -- give the caller time to get their end of the call setup
>        h <- update IncHits
>        streamFile "queue-thereare" [] Nothing
>        sayNumber h []
>        streamFile "vm-goodbye" [] Nothing
>        hangUp Nothing
>        return ()

 <h2>Hooking it up</h2>
<p>To test the application, first we need to update the asterisk dialplan to call our AGI application. Something like this should do the trick (be sure to reload the dialplan after modifying <code>extensions.conf</code>):</p>
<pre>
[default]
exten => 31415,1,AGI(agi://127.0.0.1)
</pre>
<p>Then we just run the server:</p>
<pre>
 $ runhaskell HitCounter.lhs
</pre>
<p>Now, if we dial <code>31415</code> the magic should happen.</p>
<h2>Summary</h2>
<p>The above code is a good starting template for a more interesting AGI application. Note that caller number is a bit fuzzy. The caller number is determined by who gets to the <code>update</code> function first -- which could be different than who actually connected to the asterisk server first. </p>
</body>
</html>
