From 277314a26087276cfef83abbeb8b61bcd3d039fa Mon Sep 17 00:00:00 2001
From: Eduardo Trujillo <ed@chromabits.com>
Date: Sat, 13 Feb 2016 23:16:20 -0500
Subject: [PATCH] New experimental server

---
 blog.cabal    |  24 ++++++++---
 css/app.css   |   4 +-
 scss/app.scss |   2 +-
 server.hs     | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++
 stack.yaml    |   2 +-
 5 files changed, 130 insertions(+), 10 deletions(-)
 create mode 100644 server.hs

diff --git a/blog.cabal b/blog.cabal
index 7e9888a..e0f37d9 100644
--- a/blog.cabal
+++ b/blog.cabal
@@ -1,13 +1,13 @@
 name:                blog
 version:             0.1.0.0
-synopsis:            Hakyll project template from stack
+synopsis:            Chromabits blog generator and server
 description:         Please see README.md
-homepage:            http://github.com/githubuser/blog#readme
-license:             BSD3
+homepage:            http://chromabits.com
+license:             MIT
 license-file:        LICENSE
-author:              Author name here
-maintainer:          example@example.com
-copyright:           2010 Author Here
+author:              Eduardo Trujillo
+maintainer:          ed@chromabits.com
+copyright:           2015-2016 Eduardo Trujillo
 category:            Web
 build-type:          Simple
 cabal-version:       >=1.10
@@ -25,3 +25,15 @@ executable blog
                        containers == 0.5.*,
                        pandoc == 1.*,
                        highlighting-kate == 0.6.*
+
+executable server
+  main-is:             server.hs
+  default-language:    Haskell2010
+  ghc-options:         -threaded
+  build-depends:       base == 4.*,
+                       text,
+                       bytestring == 0.10.*,
+                       warp == 3.*,
+                       wai == 3.*,
+                       wai-extra <= 3.0.14,
+                       wai-app-static == 3.*
diff --git a/css/app.css b/css/app.css
index a96b461..93cf186 100644
--- a/css/app.css
+++ b/css/app.css
@@ -2895,8 +2895,8 @@ table.hover tr:nth-of-type(even):hover {
  * -------------------------- */
 @font-face {
   font-family: 'FontAwesome';
-  src: url("/fonts//fontawesome-webfont.eot?v=4.5.0");
-  src: url("/fonts//fontawesome-webfont.eot?#iefix&v=4.5.0") format("embedded-opentype"), url("/fonts//fontawesome-webfont.woff2?v=4.5.0") format("woff2"), url("/fonts//fontawesome-webfont.woff?v=4.5.0") format("woff"), url("/fonts//fontawesome-webfont.ttf?v=4.5.0") format("truetype"), url("/fonts//fontawesome-webfont.svg?v=4.5.0#fontawesomeregular") format("svg");
+  src: url("/fonts/fontawesome-webfont.eot?v=4.5.0");
+  src: url("/fonts/fontawesome-webfont.eot?#iefix&v=4.5.0") format("embedded-opentype"), url("/fonts/fontawesome-webfont.woff2?v=4.5.0") format("woff2"), url("/fonts/fontawesome-webfont.woff?v=4.5.0") format("woff"), url("/fonts/fontawesome-webfont.ttf?v=4.5.0") format("truetype"), url("/fonts/fontawesome-webfont.svg?v=4.5.0#fontawesomeregular") format("svg");
   font-weight: normal;
   font-style: normal; }
 
diff --git a/scss/app.scss b/scss/app.scss
index 7eeebdb..f7b71e6 100644
--- a/scss/app.scss
+++ b/scss/app.scss
@@ -39,7 +39,7 @@
 @include foundation-tooltip;
 @include foundation-top-bar;
 
-$fa-font-path: "/fonts/";
+$fa-font-path: "/fonts";
 @import "font-awesome";
 
 @import "code";
diff --git a/server.hs b/server.hs
new file mode 100644
index 0000000..b7d3f1b
--- /dev/null
+++ b/server.hs
@@ -0,0 +1,108 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+import qualified Data.ByteString as BS (ByteString, pack)
+import Data.String (fromString)
+import qualified Data.Text as T (Text, concat, pack)
+import qualified Data.Text.Encoding as TE (encodeUtf8)
+import Data.Maybe (mapMaybe, fromMaybe)
+import System.Environment (lookupEnv)
+import Network.Wai (Application, Middleware, pathInfo)
+import Network.Wai.Handler.Warp (run)
+import Network.Wai.Application.Static (staticApp
+                                      , defaultWebAppSettings
+                                      , ssIndices
+                                      , ssRedirectToIndex
+                                      , ssAddTrailingSlash
+                                      , ss404Handler
+                                      )
+import WaiAppStatic.Types (toPiece)
+import Network.Wai.Middleware.RequestLogger (logStdout)
+import Network.Wai.Middleware.Gzip (gzip, def)
+import Network.Wai.Middleware.ForceSSL (forceSSL)
+import Network.Wai.Middleware.ForceDomain (forceDomain)
+import Network.Wai.Middleware.Vhost (redirectTo)
+
+-- | The core application.
+-- It serves files from `_site` whic is where Hakyll will place the generated
+-- site.
+staticSite :: Application
+staticSite = staticApp
+              (defaultWebAppSettings $ fromString "_site")
+              { ssIndices  = mapMaybe (toPiece . T.pack) ["index.html"]
+              , ssRedirectToIndex = False
+              , ssAddTrailingSlash = True
+              , ss404Handler = Just redirectApp
+              }
+
+-- | 404 handler.
+-- We will redirect users back to the homepage if the reosurce they are looking
+-- for is not found.
+redirectApp :: Application
+redirectApp req sendResponse = sendResponse $ redirectTo "/"
+
+-- | Gzip compression middleware.
+gzipMiddleware :: Middleware
+gzipMiddleware = gzip def
+
+-- | Domain redirection middleware.
+-- When the site is live, we want to redirect users to the right domain name
+-- regarles of whether they arrive from a www. domain, the server's IP address
+-- or a spoof domain which is pointing to this server.
+domainMiddleware :: Middleware
+domainMiddleware = forceDomain
+                    (\domain -> case domain of
+                                 "localhost" -> Nothing
+                                 "chromabits.com" -> Nothing
+                                 _ -> Just "chromabits.com")
+
+-- | De-indefify middleware.
+-- Redirects any path ending in `/index.html` to just `/`.
+deindexifyMiddleware :: Middleware
+deindexifyMiddleware app req sendResponse =
+  if maybeLast (pathInfo req) == Just "index.html"
+     then sendResponse $ redirectTo newPath
+     else app req sendResponse
+      where
+        newPath :: BS.ByteString
+        newPath = TE.encodeUtf8 $ T.concat (map prefixSlash oldPath)
+
+        oldPath :: [T.Text]
+        oldPath = init $ pathInfo req
+
+        prefixSlash :: T.Text -> T.Text
+        prefixSlash x = T.concat ["/", x]
+
+maybeLast :: [a] -> Maybe a
+maybeLast xs = case xs of
+                 [] -> Nothing
+                 _ -> Just (last xs)
+
+-- | Serves a WAI Application on the specified port.
+-- The target port is printed to stdout before hand, which can be useful for
+-- debugging purposes.
+listen :: Int -> Application -> IO ()
+listen port app = do
+  -- Inform which port we will be listening on.
+  putStrLn $ "Listening on port " ++ show port ++ "..."
+  -- Serve the WAI app using Warp
+  run port app
+
+-- | The entry point of the server application.
+main :: IO ()
+main = do
+  stage <- lookupEnv "BLOG_STAGE"
+
+  -- Depending on the stage we will choose a different set of middleware to
+  -- apply to the application.
+  case fromMaybe "dev" stage of
+    -- "Production"
+    "live" -> listen 80 (logStdout 
+                        $ domainMiddleware
+                        $ deindexifyMiddleware
+                        $ gzipMiddleware staticSite
+                        )
+    -- "Development"
+    _ -> listen 9090 (logStdout 
+                     $ deindexifyMiddleware 
+                     $ gzipMiddleware staticSite
+                     )
diff --git a/stack.yaml b/stack.yaml
index ed00a51..e64e9f5 100644
--- a/stack.yaml
+++ b/stack.yaml
@@ -1,7 +1,7 @@
 # For more information, see: https://github.com/commercialhaskell/stack/blob/release/doc/yaml_configuration.md
 
 # Specifies the GHC version and set of packages available (e.g., lts-3.5, nightly-2015-09-21, ghc-7.10.2)
-resolver: lts-3.14
+resolver: lts-5.2
 
 # Local packages, usually specified by relative directory name
 packages:
-- 
GitLab