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
|
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
-- | simple server offering linting "as a service"
module Main where
import Cli.Extras (mkDefaultCliConfig, runCli)
import Control.Concurrent (MVar, newMVar)
import Control.Monad.IO.Class (liftIO)
import qualified Data.ByteString.Lazy.Char8 as C8
import Handlers (App, statusImpl, submitImpl)
import Network.Wai.Handler.Warp (run)
import Servant (Application, Get, Handler,
HasServer (ServerT), JSON,
Proxy (Proxy), ReqBody,
ServerError (errBody), err500,
hoistServer, serve, throwError,
type (:<|>) (..), type (:>), Post)
import Server (Config (..), JobStatus,
RemoteRef (..), State, loadConfig)
{-
Needed:
- admin overview (perhaps on seperate port?)
- in json:
- submit a repository link & ref name, get back job id
- look up a lint status by job id
- in html
- look up a lint status, pretty-printed
- front page with overview & links
- possibly a "update & relint" button?
- links to documentation
-}
-- | Main API type
type API format =
"submit" :> ReqBody '[JSON] RemoteRef :> Post '[format] ()
:<|> "status" :> ReqBody '[JSON] RemoteRef :> Get '[format] JobStatus
-- | API's implementation
jsonAPI :: Config True -> MVar State -> ServerT (API JSON) App
jsonAPI config state =
submitImpl config state
:<|> statusImpl state
-- | make an application; convert any cli errors into a 500
app :: Config True -> MVar State -> Application
app config =
serve api . hoistServer api conv . jsonAPI config
where api = Proxy @(API JSON)
conv :: App a -> Handler a
conv m = do
config <- liftIO $ mkDefaultCliConfig []
res <- runCli config m
case res of
Right a -> pure a
Left err -> throwError (err500 { errBody = C8.pack (show err) })
main :: IO ()
main = do
state <- newMVar (mempty :: State)
let config = Config "/tmp" 8080 "main.json" "./config.json"
config' <- loadConfig config
run (port config) (app config' state)
|