33module Lapse.Web.Server where
44
55import Control.Monad.IO.Class (liftIO )
6- import Control.Monad.State (evalStateT , get , lift )
76import Data.ByteString.Char8 qualified as BC
87import Data.ByteString.Lazy.Char8 qualified as BCL
9- import Data.Map.Strict (elems , empty , fromList , insert , keys , (!?) )
8+ import Data.Map.Strict (elems , empty , fromList , keys , (!?) )
109import Data.Typeable (cast )
11- import Lapse.Lambda (UnList (.. ), unList )
1210import Lapse.Types (Func , TBox (.. ), Value (.. ), ext )
13- import Lapse.Web.Types (URL , WServer (.. ))
11+ import Lapse.Web.Types (URL , WBody , WServer (.. ))
1412import Network.HTTP.Types (status200 , status400 , status404 , urlDecode )
1513import Network.Wai qualified as W
1614import Network.Wai.Handler.Warp qualified as WRP
1715
18- unString :: Value m -> String
19- unString (String s) = s
20- unString _ = error " Error: expected string but got not string"
21-
2216parseUrlPath :: String -> URL
2317parseUrlPath url =
2418 let (path, query) = break (== ' ?' ) url
@@ -40,41 +34,8 @@ splitOn delimiter str =
4034 [] -> []
4135 (_ : xs) -> splitOn delimiter xs
4236
43- unString' :: Value m -> String
44- unString' (String s) = s
45- unString' v = show v
46-
47- lroutG :: Func IO
48- lroutG (Pair (String url) (Pair args' (Pair (Function f) (Pair (External (TBox srv)) Nil )))) = do
49- st <- get
50- cnt <- lift get
51- case cast @ _ @ WServer srv of
52- Just s@ WServer {routesGET} ->
53- let tm x =
54- pure $
55- ext
56- s
57- { routesGET =
58- insert
59- url
60- ( x
61- , (`evalStateT` cnt)
62- . (`evalStateT` st)
63- . fmap (BCL. pack . unString')
64- . f
65- . foldr (Pair . String ) Nil
66- )
67- routesGET
68- }
69- in case unList args' of
70- Single (String arg) -> tm [arg]
71- Proper args -> tm $ map unString args
72- _ -> lroutG Nil
73- Nothing -> lroutG Nil
74- lroutG _ = error " routeGET error, valid syntax: routeGET <url> <args> <func>"
75-
76- respond :: WServer -> URL -> IO W. Response
77- respond WServer {routesGET} (url, params) =
37+ respond :: WServer -> URL -> WBody -> IO W. Response
38+ respond WServer {routesGET, routesPOST} (url, params) =
7839 case routesGET !? url of
7940 Just (crNames, f) -> do
8041 let names = keys params
@@ -83,11 +44,23 @@ respond WServer{routesGET} (url, params) =
8344 let validNames = foldr ((&&) . uncurry (==) ) True names'
8445 let validLengths = (length names == length crNames) && (length values == length names)
8546 if validNames && validLengths
86- then do
47+ then const do
8748 res <- f values
8849 pure $ W. responseLBS status200 [] res
89- else pure $ W. responseLBS status400 [] $ BCL. pack " Bad Request"
90- Nothing -> pure $ W. responseLBS status404 [] $ BCL. pack $ " No such endpoint: " ++ url
50+ else const $ pure $ W. responseLBS status400 [] $ BCL. pack " Bad Request"
51+ Nothing -> case routesPOST !? url of
52+ Just (crNames, f) -> do
53+ let names = keys params
54+ let values = elems params
55+ let names' = zip names crNames
56+ let validNames = foldr ((&&) . uncurry (==) ) True names'
57+ let validLengths = (length names == length crNames) && (length values == length names)
58+ if validNames && validLengths
59+ then \ body -> do
60+ res <- f body values
61+ pure $ W. responseLBS status200 [] res
62+ else const $ pure $ W. responseLBS status400 [] $ BCL. pack " Bad Request"
63+ Nothing -> const $ pure $ W. responseLBS status404 [] $ BCL. pack $ " No such endpoint: " ++ url
9164
9265lserve :: Func IO
9366lserve (Pair (External (TBox srv)) Nil ) =
@@ -96,12 +69,12 @@ lserve (Pair (External (TBox srv)) Nil) =
9669 liftIO
9770 ( WRP. run port \ req res ->
9871 let path r = BC. unpack $ urlDecode False $ W. rawPathInfo r <> W. rawQueryString r
99- in respond s (parseUrlPath $ path req) >>= res
72+ in W. strictRequestBody req >>= \ body -> respond s (parseUrlPath $ path req) ( BCL. unpack body ) >>= res
10073 )
10174 >> pure Nil
10275 Nothing -> lserve Nil
10376lserve _ = error " serve expected exactly one argument :: WServer"
10477
10578lserver :: Func IO
106- lserver (Pair (Number port) Nil ) = pure $ ext WServer {port, routesGET = empty}
79+ lserver (Pair (Number port) Nil ) = pure $ ext WServer {port, routesGET = empty, routesPOST = empty }
10780lserver _ = error " Expected integer port as argument to server"
0 commit comments