{-# LANGUAGE BlockArguments #-} {-# LANGUAGE MultiWayIf #-} {-# LANGUAGE OverlappingInstances #-} {-# LANGUAGE OverloadedRecordDot #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE RecordWildCards #-} {-# OPTIONS_GHC -fno-warn-orphans #-} module Main where import Conduit import Control.Arrow hiding (app) import Control.Concurrent import Control.Exception import Control.Monad import Data.Function import Data.List import Data.List.Split import Data.Maybe import Data.Tagged import Data.Text qualified as T import Data.Time.Calendar import Data.Time.Clock import Data.Time.Format.ISO8601 import Data.Time.LocalTime import Git qualified as G import Git.Libgit2 qualified as GB import Network.HTTP.Types import Network.Wai.Conduit import Network.Wai.Handler.Warp import System.Environment import System.FilePath import System.IO.Unsafe import Text.Atom.Conduit.Render import Text.Atom.Types import Text.Blaze import Text.Blaze.Html.Renderer.Utf8 import Text.Cassius import Text.Hamlet import Text.Printf import Text.XML.Stream.Render env_REPOSITORIES :: [String] env_REPOSITORIES = splitOn ":" (unsafePerformIO (getEnv "REPOSITORIES")) env_PORT :: Int env_PORT = maybe 8080 read (unsafePerformIO (lookupEnv "PORT")) main :: IO () main = do runSettings ( defaultSettings -- XXX contrary to documentation, this enables both IPv4 and IPv6 & setHost "!6" & setPort env_PORT & setBeforeMainLoop do printf "listening on %d..\n" env_PORT ) app app :: Application app req resp = do if | rawPathInfo req == "/feed" -> resp . responseStream status200 [ ("content-type", "application/atom+xml") ] $ \write _ -> do commits <- reverse . sortOn (.createdAt) <$> getCommitsConcurrently env_REPOSITORIES feedUpdated <- getCurrentTime runConduit $ renderAtomFeed AtomFeed { feedAuthors = [], feedCategories = [], feedContributors = [], feedEntries = map ( \commit -> AtomEntry { entryAuthors = [], entryCategories = [], entryContent = AtomContentInlineText TypeText <$> (snd commit.message), entryContributors = [], entryId = "feed.nomath.org/" <> commit.repository <> "/" <> commit.hash, entryLinks = [], entryPublished = Nothing, entryRights = Nothing, entrySource = Nothing, entrySummary = Nothing, entryTitle = AtomPlainText TypeText (fst commit.message), entryUpdated = commit.createdAt } ) commits, feedGenerator = Nothing, feedIcon = Nothing, feedId = "https://feed.nomath.org", feedLinks = [], feedLogo = Nothing, feedRights = Nothing, feedSubtitle = Nothing, feedTitle = AtomPlainText TypeText "feed.nomath.org", feedUpdated = feedUpdated } .| renderBuilder def .| mapM_C write | rawPathInfo req == "/" -> resp . responseStream status200 [ ("content-type", "text/html") ] $ \write _ -> do commits <- reverse . sortOn (.createdAt) <$> getCommitsConcurrently env_REPOSITORIES let commitsPerDay = (map (\xs -> (utctDay . (.createdAt) $ head xs, xs))) $ groupBy ((==) `on` (utctDay . (.createdAt))) commits write $ renderHtmlBuilder [shamlet|