summaryrefslogtreecommitdiff
path: root/Biz/Que/Site.hs
blob: f4e4a9cf6503ffb7dbacd510c61429575a291c33 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE NoImplicitPrelude #-}

-- | spawns a few processes that serve the que.run website
--
-- : out que-website
module Biz.Que.Site
  ( main,
  )
where

import Alpha
import qualified Control.Concurrent.Async as Async
import qualified Data.ByteString.Char8 as BS
import qualified Data.Ini.Config as Config
import qualified Data.Text as Text
import qualified Data.Text.IO as Text
import Network.HTTP.Req
import qualified Omni.Cli as Cli
import Omni.Test ((@=?))
import qualified Omni.Test as Test
import qualified System.Directory as Directory
import System.FilePath ((</>))
import qualified System.Process as Process

main :: IO ()
main = Cli.main <| Cli.Plan help move test pure

move :: Cli.Arguments -> IO ()
move args = do
  let (src, ns) = case (getArg "src", Text.pack </ getArg "ns") of
        (Just s, Just n) -> (s, n)
        _ -> panic "could not initialize from CLI arguments"
  mKey <- getKey ns
  putText <| "serving " <> Text.pack src <> " at " <> ns
  run mKey ns
    <| Sources
      { index = src </> "Index.md",
        client = src </> "Client.py",
        quescripts = src </> "Quescripts.md",
        style = src </> "Style.css",
        tutorial = src </> "Tutorial.md"
      }
  where
    getArg = Cli.getArg args <. Cli.argument

help :: Cli.Docopt
help =
  [Cli.docopt|
que-website

Usage:
  que-website <src> <ns>
  que-website test
|]

test :: Test.Tree
test = Test.group "Biz.Que.Site" [Test.unit "id" <| 1 @=? (1 :: Integer)]

getKey :: Namespace -> IO (Maybe Key)
getKey ns = do
  home <- Directory.getHomeDirectory
  let file = home </> ".config" </> "que.conf"
  exists <- Directory.doesFileExist file
  unless exists <| panic <| "not found: " <> Text.pack file
  conf <- Text.readFile file
  print (home </> ".config" </> "que.conf")
  auth ns
    |> Config.parseIniFile conf
    |> either errorParsingConf identity
    |> pure

errorParsingConf :: error
errorParsingConf = panic "could not parse ~/.config/que.conf"

data Sources = Sources
  { index :: FilePath,
    quescripts :: FilePath,
    client :: FilePath,
    style :: FilePath,
    tutorial :: FilePath
  }

type Namespace = Text

type Key = Text

auth :: Namespace -> Config.IniParser (Maybe Key)
auth "pub" = pure Nothing
auth ns = Config.sectionMb ns <| Config.field "key"

run :: Maybe Key -> Text -> Sources -> IO ()
run key ns Sources {..} = Async.runConcurrently actions |> void
  where
    actions =
      traverse
        Async.Concurrently
        [ toHtml index +> serve key ns "index" |> forever,
          toHtml quescripts +> serve key ns "quescripts" |> forever,
          BS.readFile client +> serve key ns "client" |> forever,
          toHtml tutorial +> serve key ns "tutorial" |> forever
        ]
    toHtml :: FilePath -> IO ByteString
    toHtml md =
      BS.pack
        </ Process.readProcess
          "pandoc"
          [ "--include-in-header",
            style,
            "-i",
            md,
            "--from",
            "markdown",
            "--to",
            "html"
          ]
          []

serve :: Maybe Key -> Namespace -> Text -> ByteString -> IO ()
serve Nothing "pub" path content =
  runReq defaultHttpConfig <| do
    _ <-
      req
        POST
        (http "que.run" /: "pub" /: path)
        (ReqBodyBs content)
        ignoreResponse
        mempty
    liftIO <| pure ()
serve Nothing p _ _ = panic <| "no auth key provided for ns: " <> p
serve (Just _) ns path content =
  runReq defaultHttpConfig <| do
    let options =
          header "Content-type" "text/html;charset=utf-8"
    -- header "Authorization" (encodeUtf8 key) <> responseTimeout maxBound
    _ <-
      req
        POST
        (http "que.run" /: ns /: path)
        (ReqBodyBs content)
        ignoreResponse
        options
    liftIO <| pure ()