feat: generalize ResponseM to any MonadAff
This commit is contained in:
parent
077112e0ea
commit
0a3ff07fa8
@ -45,7 +45,7 @@ import HTTPurple.NodeMiddleware
|
|||||||
import HTTPurple.Path (Path)
|
import HTTPurple.Path (Path)
|
||||||
import HTTPurple.Query (Query)
|
import HTTPurple.Query (Query)
|
||||||
import HTTPurple.Request (ExtRequest, Request, RequestR, fullPath)
|
import HTTPurple.Request (ExtRequest, Request, RequestR, fullPath)
|
||||||
import HTTPurple.Response (Response, ResponseM, accepted, accepted', alreadyReported, alreadyReported', badGateway, badGateway', badRequest, badRequest', conflict, conflict', continue, continue', created, created', emptyResponse, emptyResponse', expectationFailed, expectationFailed', failedDependency, failedDependency', forbidden, forbidden', found, found', gatewayTimeout, gatewayTimeout', gone, gone', hTTPVersionNotSupported, hTTPVersionNotSupported', iMUsed, iMUsed', imATeapot, imATeapot', insufficientStorage, insufficientStorage', internalServerError, internalServerError', lengthRequired, lengthRequired', locked, locked', loopDetected, loopDetected', methodNotAllowed, methodNotAllowed', misdirectedRequest, misdirectedRequest', movedPermanently, movedPermanently', multiStatus, multiStatus', multipleChoices, multipleChoices', networkAuthenticationRequired, networkAuthenticationRequired', noContent, noContent', nonAuthoritativeInformation, nonAuthoritativeInformation', notAcceptable, notAcceptable', notExtended, notExtended', notFound, notFound', notImplemented, notImplemented', notModified, notModified', ok, ok', partialContent, partialContent', payloadTooLarge, payloadTooLarge', paymentRequired, paymentRequired', permanentRedirect, permanentRedirect', preconditionFailed, preconditionFailed', preconditionRequired, preconditionRequired', processing, processing', proxyAuthenticationRequired, proxyAuthenticationRequired', rangeNotSatisfiable, rangeNotSatisfiable', requestHeaderFieldsTooLarge, requestHeaderFieldsTooLarge', requestTimeout, requestTimeout', resetContent, resetContent', response, response', seeOther, seeOther', serviceUnavailable, serviceUnavailable', switchingProtocols, switchingProtocols', temporaryRedirect, temporaryRedirect', tooManyRequests, tooManyRequests', uRITooLong, uRITooLong', unauthorized, unauthorized', unavailableForLegalReasons, unavailableForLegalReasons', unprocessableEntity, unprocessableEntity', unsupportedMediaType, unsupportedMediaType', upgradeRequired, upgradeRequired', useProxy, useProxy', variantAlsoNegotiates, variantAlsoNegotiates')
|
import HTTPurple.Response (Response, accepted, accepted', alreadyReported, alreadyReported', badGateway, badGateway', badRequest, badRequest', conflict, conflict', continue, continue', created, created', emptyResponse, emptyResponse', expectationFailed, expectationFailed', failedDependency, failedDependency', forbidden, forbidden', found, found', gatewayTimeout, gatewayTimeout', gone, gone', hTTPVersionNotSupported, hTTPVersionNotSupported', iMUsed, iMUsed', imATeapot, imATeapot', insufficientStorage, insufficientStorage', internalServerError, internalServerError', lengthRequired, lengthRequired', locked, locked', loopDetected, loopDetected', methodNotAllowed, methodNotAllowed', misdirectedRequest, misdirectedRequest', movedPermanently, movedPermanently', multiStatus, multiStatus', multipleChoices, multipleChoices', networkAuthenticationRequired, networkAuthenticationRequired', noContent, noContent', nonAuthoritativeInformation, nonAuthoritativeInformation', notAcceptable, notAcceptable', notExtended, notExtended', notFound, notFound', notImplemented, notImplemented', notModified, notModified', ok, ok', partialContent, partialContent', payloadTooLarge, payloadTooLarge', paymentRequired, paymentRequired', permanentRedirect, permanentRedirect', preconditionFailed, preconditionFailed', preconditionRequired, preconditionRequired', processing, processing', proxyAuthenticationRequired, proxyAuthenticationRequired', rangeNotSatisfiable, rangeNotSatisfiable', requestHeaderFieldsTooLarge, requestHeaderFieldsTooLarge', requestTimeout, requestTimeout', resetContent, resetContent', response, response', seeOther, seeOther', serviceUnavailable, serviceUnavailable', switchingProtocols, switchingProtocols', temporaryRedirect, temporaryRedirect', tooManyRequests, tooManyRequests', uRITooLong, uRITooLong', unauthorized, unauthorized', unavailableForLegalReasons, unavailableForLegalReasons', unprocessableEntity, unprocessableEntity', unsupportedMediaType, unsupportedMediaType', upgradeRequired, upgradeRequired', useProxy, useProxy', variantAlsoNegotiates, variantAlsoNegotiates')
|
||||||
import HTTPurple.Routes (type (<+>), catchAll, combineRoutes, mkRoute, orElse, (<+>))
|
import HTTPurple.Routes (type (<+>), catchAll, combineRoutes, mkRoute, orElse, (<+>))
|
||||||
import HTTPurple.Server
|
import HTTPurple.Server
|
||||||
( BasicRoutingSettings
|
( BasicRoutingSettings
|
||||||
@ -58,6 +58,7 @@ import HTTPurple.Server
|
|||||||
, ServerM
|
, ServerM
|
||||||
, defaultMiddlewareErrorHandler
|
, defaultMiddlewareErrorHandler
|
||||||
, serve
|
, serve
|
||||||
|
, serve'
|
||||||
, serveNodeMiddleware
|
, serveNodeMiddleware
|
||||||
)
|
)
|
||||||
import HTTPurple.Status (Status)
|
import HTTPurple.Status (Status)
|
||||||
|
@ -11,13 +11,16 @@ module HTTPurple.Request
|
|||||||
|
|
||||||
import Prelude
|
import Prelude
|
||||||
|
|
||||||
|
import Control.Monad.Error.Class (class MonadError)
|
||||||
import Data.Bifunctor (rmap)
|
import Data.Bifunctor (rmap)
|
||||||
import Data.Bitraversable (bitraverse)
|
import Data.Bitraversable (bitraverse)
|
||||||
import Data.Either (Either)
|
import Data.Either (Either)
|
||||||
import Data.Newtype (class Newtype)
|
import Data.Newtype (class Newtype)
|
||||||
import Data.String (joinWith)
|
import Data.String (joinWith)
|
||||||
import Effect.Aff (Aff)
|
import Effect.Aff (Aff)
|
||||||
|
import Effect.Aff.Class (class MonadAff)
|
||||||
import Effect.Class (class MonadEffect, liftEffect)
|
import Effect.Class (class MonadEffect, liftEffect)
|
||||||
|
import Effect.Exception (Error)
|
||||||
import Foreign.Object (isEmpty, toArrayWithKey)
|
import Foreign.Object (isEmpty, toArrayWithKey)
|
||||||
import HTTPurple.Body (RequestBody)
|
import HTTPurple.Body (RequestBody)
|
||||||
import HTTPurple.Body (read) as Body
|
import HTTPurple.Body (read) as Body
|
||||||
@ -97,16 +100,18 @@ mkRequest request route = do
|
|||||||
|
|
||||||
-- | Given an HTTP `Request` object, this method will convert it to an HTTPurple
|
-- | Given an HTTP `Request` object, this method will convert it to an HTTPurple
|
||||||
-- | `Request` object.
|
-- | `Request` object.
|
||||||
fromHTTPRequest :: forall route. RD.RouteDuplex' route -> IncomingMessage IMServer -> Aff (Either (Request Unit) (Request route))
|
fromHTTPRequest :: forall route m. MonadAff m => MonadError Error m => RD.RouteDuplex' route -> IncomingMessage IMServer -> m (Either (Request Unit) (Request route))
|
||||||
fromHTTPRequest route request = do
|
fromHTTPRequest route request = do
|
||||||
RD.parse route (IM.url request) #
|
RD.parse route (IM.url request) #
|
||||||
bitraverse (const $ mkRequest request unit) (mkRequest request)
|
bitraverse (const $ mkRequest request unit) (mkRequest request)
|
||||||
|
|
||||||
fromHTTPRequestUnit :: IncomingMessage IMServer -> Aff (Request Unit)
|
fromHTTPRequestUnit :: forall m. MonadEffect m => IncomingMessage IMServer -> m (Request Unit)
|
||||||
fromHTTPRequestUnit = flip mkRequest unit
|
fromHTTPRequestUnit = flip mkRequest unit
|
||||||
|
|
||||||
fromHTTPRequestExt ::
|
fromHTTPRequestExt ::
|
||||||
forall ctx ctxRL thru route.
|
forall ctx ctxRL thru route m.
|
||||||
|
MonadAff m =>
|
||||||
|
MonadError Error m =>
|
||||||
Union ctx thru ctx =>
|
Union ctx thru ctx =>
|
||||||
Nub (RequestR route ctx) (RequestR route ctx) =>
|
Nub (RequestR route ctx) (RequestR route ctx) =>
|
||||||
RowToList ctx ctxRL =>
|
RowToList ctx ctxRL =>
|
||||||
@ -114,7 +119,7 @@ fromHTTPRequestExt ::
|
|||||||
RD.RouteDuplex' route ->
|
RD.RouteDuplex' route ->
|
||||||
Proxy ctx ->
|
Proxy ctx ->
|
||||||
IncomingMessage IMServer ->
|
IncomingMessage IMServer ->
|
||||||
Aff (Either (Request Unit) (ExtRequestNT route ctx))
|
m (Either (Request Unit) (ExtRequestNT route ctx))
|
||||||
fromHTTPRequestExt route _ nodeRequest = do
|
fromHTTPRequestExt route _ nodeRequest = do
|
||||||
let
|
let
|
||||||
extension :: Record ctx
|
extension :: Record ctx
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
module HTTPurple.Response
|
module HTTPurple.Response
|
||||||
( Response
|
( Response
|
||||||
, ResponseM
|
|
||||||
, send
|
, send
|
||||||
, response
|
, response
|
||||||
, response'
|
, response'
|
||||||
@ -145,11 +144,6 @@ import HTTPurple.Status (Status)
|
|||||||
import HTTPurple.Status (accepted, alreadyReported, badGateway, badRequest, conflict, continue, created, expectationFailed, failedDependency, forbidden, found, gatewayTimeout, gone, hTTPVersionNotSupported, iMUsed, imATeapot, insufficientStorage, internalServerError, lengthRequired, locked, loopDetected, methodNotAllowed, misdirectedRequest, movedPermanently, multiStatus, multipleChoices, networkAuthenticationRequired, noContent, nonAuthoritativeInformation, notAcceptable, notExtended, notFound, notImplemented, notModified, ok, partialContent, payloadTooLarge, paymentRequired, permanentRedirect, preconditionFailed, preconditionRequired, processing, proxyAuthenticationRequired, rangeNotSatisfiable, requestHeaderFieldsTooLarge, requestTimeout, resetContent, seeOther, serviceUnavailable, switchingProtocols, temporaryRedirect, tooManyRequests, uRITooLong, unauthorized, unavailableForLegalReasons, unprocessableEntity, unsupportedMediaType, upgradeRequired, useProxy, variantAlsoNegotiates, write) as Status
|
import HTTPurple.Status (accepted, alreadyReported, badGateway, badRequest, conflict, continue, created, expectationFailed, failedDependency, forbidden, found, gatewayTimeout, gone, hTTPVersionNotSupported, iMUsed, imATeapot, insufficientStorage, internalServerError, lengthRequired, locked, loopDetected, methodNotAllowed, misdirectedRequest, movedPermanently, multiStatus, multipleChoices, networkAuthenticationRequired, noContent, nonAuthoritativeInformation, notAcceptable, notExtended, notFound, notImplemented, notModified, ok, partialContent, payloadTooLarge, paymentRequired, permanentRedirect, preconditionFailed, preconditionRequired, processing, proxyAuthenticationRequired, rangeNotSatisfiable, requestHeaderFieldsTooLarge, requestTimeout, resetContent, seeOther, serviceUnavailable, switchingProtocols, temporaryRedirect, tooManyRequests, uRITooLong, unauthorized, unavailableForLegalReasons, unprocessableEntity, unsupportedMediaType, upgradeRequired, useProxy, variantAlsoNegotiates, write) as Status
|
||||||
import Node.HTTP.Types (ServerResponse)
|
import Node.HTTP.Types (ServerResponse)
|
||||||
|
|
||||||
-- | The `ResponseM` type simply conveniently wraps up an HTTPurple monad that
|
|
||||||
-- | returns a response. This type is the return type of all router/route
|
|
||||||
-- | methods.
|
|
||||||
type ResponseM = Aff Response
|
|
||||||
|
|
||||||
-- | A `Response` is a status code, headers, and a body.
|
-- | A `Response` is a status code, headers, and a body.
|
||||||
type Response =
|
type Response =
|
||||||
{ status :: Status
|
{ status :: Status
|
||||||
|
@ -13,8 +13,9 @@ import Control.Alt ((<|>))
|
|||||||
import Data.Either (Either(..))
|
import Data.Either (Either(..))
|
||||||
import Data.Generic.Rep (class Generic)
|
import Data.Generic.Rep (class Generic)
|
||||||
import Data.Profunctor.Choice ((|||))
|
import Data.Profunctor.Choice ((|||))
|
||||||
|
import Effect.Aff.Class (class MonadAff)
|
||||||
import HTTPurple.Request (Request)
|
import HTTPurple.Request (Request)
|
||||||
import HTTPurple.Response (ResponseM)
|
import HTTPurple.Response (Response)
|
||||||
import Record as Record
|
import Record as Record
|
||||||
import Routing.Duplex as RD
|
import Routing.Duplex as RD
|
||||||
import Routing.Duplex.Generic as RG
|
import Routing.Duplex.Generic as RG
|
||||||
@ -39,11 +40,12 @@ infixr 3 combineRoutes as <+>
|
|||||||
|
|
||||||
-- | Combine two request handlers.
|
-- | Combine two request handlers.
|
||||||
orElse ::
|
orElse ::
|
||||||
forall left right.
|
forall left right m.
|
||||||
(Request left -> ResponseM) ->
|
MonadAff m =>
|
||||||
(Request right -> ResponseM) ->
|
(Request left -> m Response) ->
|
||||||
|
(Request right -> m Response) ->
|
||||||
Request (left <+> right) ->
|
Request (left <+> right) ->
|
||||||
ResponseM
|
m Response
|
||||||
orElse leftRouter _ request@{ route: Left l } = leftRouter $ Record.set (Proxy :: _ "route") l request
|
orElse leftRouter _ request@{ route: Left l } = leftRouter $ Record.set (Proxy :: _ "route") l request
|
||||||
orElse _ rightRouter request@{ route: Right r } = rightRouter $ Record.set (Proxy :: _ "route") r request
|
orElse _ rightRouter request@{ route: Right r } = rightRouter $ Record.set (Proxy :: _ "route") r request
|
||||||
|
|
||||||
|
@ -9,26 +9,29 @@ module HTTPurple.Server
|
|||||||
, ServerM
|
, ServerM
|
||||||
, defaultMiddlewareErrorHandler
|
, defaultMiddlewareErrorHandler
|
||||||
, serve
|
, serve
|
||||||
|
, serve'
|
||||||
, serveNodeMiddleware
|
, serveNodeMiddleware
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Prelude
|
import Prelude
|
||||||
|
|
||||||
import Control.Monad.Cont (runContT)
|
import Control.Monad.Cont (runContT)
|
||||||
|
import Control.Monad.Error.Class (class MonadError)
|
||||||
import Data.Maybe (Maybe(..), fromMaybe)
|
import Data.Maybe (Maybe(..), fromMaybe)
|
||||||
import Data.Newtype (unwrap)
|
import Data.Newtype (unwrap)
|
||||||
import Data.Posix.Signal (Signal(..))
|
import Data.Posix.Signal (Signal(..))
|
||||||
import Data.Profunctor (lcmap)
|
import Data.Profunctor (lcmap)
|
||||||
import Data.Profunctor.Choice ((|||))
|
import Data.Profunctor.Choice ((|||))
|
||||||
import Effect (Effect)
|
import Effect (Effect)
|
||||||
import Effect.Aff (Aff, catchError, message, runAff)
|
import Effect.Aff (Aff, catchError, launchAff_, message)
|
||||||
import Effect.Class (liftEffect)
|
import Effect.Aff.Class (class MonadAff)
|
||||||
|
import Effect.Class (class MonadEffect, liftEffect)
|
||||||
import Effect.Class.Console (log)
|
import Effect.Class.Console (log)
|
||||||
import Effect.Console (error)
|
import Effect.Console (error)
|
||||||
import Effect.Exception (Error)
|
import Effect.Exception (Error)
|
||||||
import HTTPurple.NodeMiddleware (MiddlewareResult(..), NextInvocation(..), NodeMiddlewareStack(..))
|
import HTTPurple.NodeMiddleware (MiddlewareResult(..), NextInvocation(..), NodeMiddlewareStack(..))
|
||||||
import HTTPurple.Request (ExtRequest, ExtRequestNT, Request, RequestR, fromHTTPRequestExt, fromHTTPRequestUnit)
|
import HTTPurple.Request (ExtRequest, ExtRequestNT, Request, RequestR, fromHTTPRequestExt, fromHTTPRequestUnit)
|
||||||
import HTTPurple.Response (Response, ResponseM, internalServerError, notFound, send)
|
import HTTPurple.Response (Response, internalServerError, notFound, send)
|
||||||
import Justifill (justifill)
|
import Justifill (justifill)
|
||||||
import Justifill.Fillable (class FillableFields)
|
import Justifill.Fillable (class FillableFields)
|
||||||
import Justifill.Justifiable (class JustifiableFields)
|
import Justifill.Justifiable (class JustifiableFields)
|
||||||
@ -58,22 +61,22 @@ type ServerM = Effect (Effect Unit -> Effect Unit)
|
|||||||
|
|
||||||
data ClosingHandler = DefaultClosingHandler | NoClosingHandler
|
data ClosingHandler = DefaultClosingHandler | NoClosingHandler
|
||||||
|
|
||||||
type ListenOptionsR =
|
type ListenOptionsR m =
|
||||||
( hostname :: Maybe String
|
( hostname :: Maybe String
|
||||||
, port :: Maybe Int
|
, port :: Maybe Int
|
||||||
, backlog :: Maybe Int
|
, backlog :: Maybe Int
|
||||||
, closingHandler :: Maybe ClosingHandler
|
, closingHandler :: Maybe ClosingHandler
|
||||||
, notFoundHandler :: Maybe (Request Unit -> ResponseM)
|
, notFoundHandler :: Maybe (Request Unit -> m Response)
|
||||||
, onStarted :: Maybe (Effect Unit)
|
, onStarted :: Maybe (m Unit)
|
||||||
, certFile :: Maybe String
|
, certFile :: Maybe String
|
||||||
, keyFile :: Maybe String
|
, keyFile :: Maybe String
|
||||||
)
|
)
|
||||||
|
|
||||||
type ListenOptions = { | ListenOptionsR }
|
type ListenOptions m = { | ListenOptionsR m }
|
||||||
|
|
||||||
type RoutingSettingsR route output r =
|
type RoutingSettingsR m route output r =
|
||||||
( route :: RD.RouteDuplex' route
|
( route :: RD.RouteDuplex' route
|
||||||
, router :: ExtRequest route output -> ResponseM
|
, router :: ExtRequest route output -> m Response
|
||||||
| r
|
| r
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -82,104 +85,112 @@ type MiddlewareSettingsR input output =
|
|||||||
( nodeMiddleware :: NodeMiddlewareStack input output
|
( nodeMiddleware :: NodeMiddlewareStack input output
|
||||||
)
|
)
|
||||||
|
|
||||||
type BasicRoutingSettings route = { | RoutingSettingsR route () () }
|
type BasicRoutingSettings m route = { | RoutingSettingsR m route () () }
|
||||||
|
|
||||||
type ExtRoutingSettings :: Type -> Row Type -> Row Type -> Type
|
type ExtRoutingSettings :: (Type -> Type) -> Type -> Row Type -> Row Type -> Type
|
||||||
type ExtRoutingSettings route input output = { | RoutingSettingsR route output + MiddlewareSettingsR input output }
|
type ExtRoutingSettings m route input output = { | RoutingSettingsR m route output + MiddlewareSettingsR input output }
|
||||||
|
|
||||||
-- | Given a router, handle unhandled exceptions it raises by
|
-- | Given a router, handle unhandled exceptions it raises by
|
||||||
-- | responding with 500 Internal Server Error.
|
-- | responding with 500 Internal Server Error.
|
||||||
onError500 :: forall request. (request -> ResponseM) -> request -> ResponseM
|
onError500 :: forall m request. MonadError Error m => MonadAff m => (request -> m Response) -> request -> m Response
|
||||||
onError500 router request =
|
onError500 router request =
|
||||||
catchError (router request) \err -> do
|
catchError (router request) \err -> do
|
||||||
liftEffect $ error $ message err
|
liftEffect $ error $ message err
|
||||||
internalServerError "Internal server error"
|
internalServerError "Internal server error"
|
||||||
|
|
||||||
defaultMiddlewareErrorHandler :: Error -> Request Unit -> Aff Response
|
defaultMiddlewareErrorHandler :: forall m. MonadAff m => Error -> Request Unit -> m Response
|
||||||
defaultMiddlewareErrorHandler err _ = do
|
defaultMiddlewareErrorHandler err _ = do
|
||||||
liftEffect $ error $ message err
|
liftEffect $ error $ message err
|
||||||
internalServerError "Internal server error"
|
internalServerError "Internal server error"
|
||||||
|
|
||||||
-- | handle requests without a routing adt.
|
-- | handle requests without a routing adt.
|
||||||
handleRequestUnit ::
|
handleRequestUnit :: forall m.
|
||||||
(Request Unit -> ResponseM) ->
|
MonadError Error m =>
|
||||||
|
MonadAff m =>
|
||||||
|
(Request Unit -> m Response) ->
|
||||||
IncomingMessage IMServer ->
|
IncomingMessage IMServer ->
|
||||||
ServerResponse ->
|
ServerResponse ->
|
||||||
Effect Unit
|
m Unit
|
||||||
handleRequestUnit router request httpresponse =
|
handleRequestUnit router request httpresponse =
|
||||||
void $ runAff (\_ -> pure unit) $ fromHTTPRequestUnit request
|
void $ fromHTTPRequestUnit request
|
||||||
>>= (onError500 router)
|
>>= (onError500 router)
|
||||||
>>= send httpresponse
|
>>= send httpresponse
|
||||||
|
|
||||||
-- | This function takes a record containing the
|
-- | This function takes a record containing the
|
||||||
-- | * route - the routing adt
|
-- | * route - the routing adt
|
||||||
-- | * router - the request handler (a method which takes a `Request` and returns a
|
-- | * router - the request handler (a method which takes a `Request` and returns a
|
||||||
-- | `ResponseM`)
|
-- | `m Response`)
|
||||||
-- | * notFoundHandler - a handler to handle 404s
|
-- | * notFoundHandler - a handler to handle 404s
|
||||||
-- | as well as an HTTP `Request` and an HTTP `Response`. It runs the
|
-- | as well as an HTTP `Request` and an HTTP `Response`. It runs the
|
||||||
-- | request, extracts the `Response` from the `ResponseM`, and sends the
|
-- | request, extracts the `Response` from the `m Response`, and sends the
|
||||||
-- | `Response` to the HTTP `Response`.
|
-- | `Response` to the HTTP `Response`.
|
||||||
handleExtRequest ::
|
handleExtRequest ::
|
||||||
forall ctx ctxRL thru route.
|
forall m ctx ctxRL thru route.
|
||||||
|
MonadError Error m =>
|
||||||
|
MonadAff m =>
|
||||||
Union ctx thru ctx =>
|
Union ctx thru ctx =>
|
||||||
RowToList ctx ctxRL =>
|
RowToList ctx ctxRL =>
|
||||||
Keys ctx =>
|
Keys ctx =>
|
||||||
Nub (RequestR route ctx) (RequestR route ctx) =>
|
Nub (RequestR route ctx) (RequestR route ctx) =>
|
||||||
{ route :: RD.RouteDuplex' route
|
{ route :: RD.RouteDuplex' route
|
||||||
, router :: ExtRequestNT route ctx -> ResponseM
|
, router :: ExtRequestNT route ctx -> m Response
|
||||||
, notFoundHandler :: Request Unit -> ResponseM
|
, notFoundHandler :: Request Unit -> m Response
|
||||||
} ->
|
} ->
|
||||||
IncomingMessage IMServer ->
|
IncomingMessage IMServer ->
|
||||||
ServerResponse ->
|
ServerResponse ->
|
||||||
Aff Unit
|
m Unit
|
||||||
handleExtRequest { route, router, notFoundHandler } req resp = do
|
handleExtRequest { route, router, notFoundHandler } req resp = do
|
||||||
httpurpleReq <- fromHTTPRequestExt route (Proxy :: Proxy ctx) req
|
httpurpleReq <- fromHTTPRequestExt route (Proxy :: Proxy ctx) req
|
||||||
httpurpleResp <- (notFoundHandler ||| onError500 router) httpurpleReq
|
httpurpleResp <- (notFoundHandler ||| onError500 router) httpurpleReq
|
||||||
send resp httpurpleResp
|
send resp httpurpleResp
|
||||||
|
|
||||||
handleRequest ::
|
handleRequest ::
|
||||||
forall ctx ctxRL thru route.
|
forall ctx ctxRL thru route m.
|
||||||
|
MonadAff m =>
|
||||||
|
MonadError Error m =>
|
||||||
Union ctx thru ctx =>
|
Union ctx thru ctx =>
|
||||||
RowToList ctx ctxRL =>
|
RowToList ctx ctxRL =>
|
||||||
Keys ctx =>
|
Keys ctx =>
|
||||||
Nub (RequestR route ctx) (RequestR route ctx) =>
|
Nub (RequestR route ctx) (RequestR route ctx) =>
|
||||||
{ route :: RD.RouteDuplex' route
|
{ route :: RD.RouteDuplex' route
|
||||||
, router :: ExtRequestNT route ctx -> ResponseM
|
, router :: ExtRequestNT route ctx -> m Response
|
||||||
, notFoundHandler :: Request Unit -> ResponseM
|
, notFoundHandler :: Request Unit -> m Response
|
||||||
} ->
|
} ->
|
||||||
IncomingMessage IMServer ->
|
IncomingMessage IMServer ->
|
||||||
ServerResponse ->
|
ServerResponse ->
|
||||||
Effect Unit
|
m Unit
|
||||||
handleRequest settings request response = void $ runAff (\_ -> pure unit) $ handleExtRequest settings request response
|
handleRequest settings request response = void $ handleExtRequest settings request response
|
||||||
|
|
||||||
handleExtRequestWithMiddleware ::
|
handleExtRequestWithMiddleware ::
|
||||||
forall input output outputRL thru route.
|
forall input output outputRL thru route m.
|
||||||
|
MonadAff m =>
|
||||||
|
MonadError Error m =>
|
||||||
Union output thru output =>
|
Union output thru output =>
|
||||||
RowToList output outputRL =>
|
RowToList output outputRL =>
|
||||||
Keys output =>
|
Keys output =>
|
||||||
Nub (RequestR route output) (RequestR route output) =>
|
Nub (RequestR route output) (RequestR route output) =>
|
||||||
{ route :: RD.RouteDuplex' route
|
{ route :: RD.RouteDuplex' route
|
||||||
, nodeMiddleware :: NodeMiddlewareStack input output
|
, nodeMiddleware :: NodeMiddlewareStack input output
|
||||||
, router :: ExtRequestNT route output -> ResponseM
|
, router :: ExtRequestNT route output -> m Response
|
||||||
, notFoundHandler :: Request Unit -> ResponseM
|
, notFoundHandler :: Request Unit -> m Response
|
||||||
} ->
|
} ->
|
||||||
IncomingMessage IMServer ->
|
IncomingMessage IMServer ->
|
||||||
ServerResponse ->
|
ServerResponse ->
|
||||||
Effect Unit
|
m Unit
|
||||||
handleExtRequestWithMiddleware { route, nodeMiddleware: NodeMiddlewareStack middleware, router, notFoundHandler } req resp = void $ runAff (\_ -> pure unit) $ do
|
handleExtRequestWithMiddleware { route, nodeMiddleware: NodeMiddlewareStack middleware, router, notFoundHandler } req resp = void $ do
|
||||||
eff <- liftEffect $ flip runContT (coerce >>> pure) $ middleware (MiddlewareResult { request: req, response: resp, middlewareResult: NotCalled })
|
eff <- liftEffect $ flip runContT (coerce >>> pure) $ middleware (MiddlewareResult { request: req, response: resp, middlewareResult: NotCalled })
|
||||||
executeHandler eff
|
executeHandler eff
|
||||||
where
|
where
|
||||||
|
|
||||||
executeHandler :: MiddlewareResult output -> Aff Unit
|
executeHandler :: MiddlewareResult output -> m Unit
|
||||||
executeHandler (MiddlewareResult { request, response, middlewareResult: ProcessingFailed error }) =
|
executeHandler (MiddlewareResult { request, response, middlewareResult: ProcessingFailed error }) =
|
||||||
liftEffect $ handleRequestUnit (defaultMiddlewareErrorHandler error) request response
|
handleRequestUnit (defaultMiddlewareErrorHandler error) request response
|
||||||
executeHandler (MiddlewareResult { request, response, middlewareResult: ProcessingSucceeded }) =
|
executeHandler (MiddlewareResult { request, response, middlewareResult: ProcessingSucceeded }) =
|
||||||
handleExtRequest { route, router, notFoundHandler } request response
|
handleExtRequest { route, router, notFoundHandler } request response
|
||||||
executeHandler (MiddlewareResult { middlewareResult: NotCalled }) =
|
executeHandler (MiddlewareResult { middlewareResult: NotCalled }) =
|
||||||
pure unit
|
pure unit
|
||||||
|
|
||||||
defaultNotFoundHandler :: forall route. Request route -> ResponseM
|
defaultNotFoundHandler :: forall route m. MonadAff m => Request route -> m Response
|
||||||
defaultNotFoundHandler = const notFound
|
defaultNotFoundHandler = const notFound
|
||||||
|
|
||||||
asExtended ::
|
asExtended ::
|
||||||
@ -190,25 +201,28 @@ asExtended ::
|
|||||||
asExtended = lcmap unwrap
|
asExtended = lcmap unwrap
|
||||||
|
|
||||||
serveInternal ::
|
serveInternal ::
|
||||||
forall route from fromRL via missing missingList input output outputRL thru.
|
forall m route from fromRL via missing missingList input output outputRL thru.
|
||||||
|
MonadAff m =>
|
||||||
|
MonadError Error m =>
|
||||||
RowToList missing missingList =>
|
RowToList missing missingList =>
|
||||||
FillableFields missingList () missing =>
|
FillableFields missingList () missing =>
|
||||||
Union via missing (ListenOptionsR) =>
|
Union via missing (ListenOptionsR m) =>
|
||||||
RowToList from fromRL =>
|
RowToList from fromRL =>
|
||||||
JustifiableFields fromRL from () via =>
|
JustifiableFields fromRL from () via =>
|
||||||
Union output thru output =>
|
Union output thru output =>
|
||||||
RowToList output outputRL =>
|
RowToList output outputRL =>
|
||||||
KeysRL outputRL =>
|
KeysRL outputRL =>
|
||||||
Nub (RequestR route output) (RequestR route output) =>
|
Nub (RequestR route output) (RequestR route output) =>
|
||||||
|
(m Unit -> Aff Unit) ->
|
||||||
{ | from } ->
|
{ | from } ->
|
||||||
Maybe (NodeMiddlewareStack input output) ->
|
Maybe (NodeMiddlewareStack input output) ->
|
||||||
{ route :: RD.RouteDuplex' route
|
{ route :: RD.RouteDuplex' route
|
||||||
, router :: ExtRequestNT route output -> ResponseM
|
, router :: ExtRequestNT route output -> m Response
|
||||||
} ->
|
} ->
|
||||||
ServerM
|
ServerM
|
||||||
serveInternal inputOptions maybeNodeMiddleware settings = do
|
serveInternal performM inputOptions maybeNodeMiddleware settings = do
|
||||||
let
|
let
|
||||||
filledOptions :: ListenOptions
|
filledOptions :: ListenOptions m
|
||||||
filledOptions = justifill inputOptions
|
filledOptions = justifill inputOptions
|
||||||
|
|
||||||
host = fromMaybe defaultHostname filledOptions.hostname
|
host = fromMaybe defaultHostname filledOptions.hostname
|
||||||
@ -221,52 +235,70 @@ serveInternal inputOptions maybeNodeMiddleware settings = do
|
|||||||
, backlog: fromMaybe 511 filledOptions.backlog
|
, backlog: fromMaybe 511 filledOptions.backlog
|
||||||
}
|
}
|
||||||
|
|
||||||
routingSettings = merge settings { notFoundHandler: fromMaybe defaultNotFoundHandler filledOptions.notFoundHandler }
|
routingSettings = merge settings { notFoundHandler: fromMaybe defaultNotFoundHandler $ filledOptions.notFoundHandler }
|
||||||
|
|
||||||
handler = case maybeNodeMiddleware of
|
handler req rep = launchAff_ $ performM $ case maybeNodeMiddleware of
|
||||||
Just nodeMiddleware -> handleExtRequestWithMiddleware $ merge routingSettings { nodeMiddleware }
|
Just nodeMiddleware -> handleExtRequestWithMiddleware (merge routingSettings { nodeMiddleware }) req rep
|
||||||
Nothing -> handleRequest routingSettings
|
Nothing -> handleRequest routingSettings req rep
|
||||||
sslOptions = { certFile: _, keyFile: _ } <$> filledOptions.certFile <*> filledOptions.keyFile
|
sslOptions = { certFile: _, keyFile: _ } <$> filledOptions.certFile <*> filledOptions.keyFile
|
||||||
netServer <- case sslOptions of
|
netServer <- case sslOptions of
|
||||||
Just { certFile, keyFile } -> do
|
Just { certFile, keyFile } -> do
|
||||||
cert' <- readFile certFile
|
cert' <- liftEffect $ readFile certFile
|
||||||
key' <- readFile keyFile
|
key' <- liftEffect $ readFile keyFile
|
||||||
server <- HTTPS.createSecureServer'
|
server <- liftEffect $ HTTPS.createSecureServer'
|
||||||
{ key: [ key' ]
|
{ key: [ key' ]
|
||||||
, cert: [ cert' ]
|
, cert: [ cert' ]
|
||||||
}
|
}
|
||||||
server # EE.on_ HServer.requestH handler
|
liftEffect $ EE.on_ HServer.requestH handler server
|
||||||
pure $ HServer.toNetServer server
|
pure $ HServer.toNetServer server
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
server <- HTTP.createServer
|
server <- liftEffect $ HTTP.createServer
|
||||||
server # EE.on_ HServer.requestH handler
|
liftEffect $ EE.on_ HServer.requestH handler server
|
||||||
pure $ HServer.toNetServer server
|
pure $ HServer.toNetServer server
|
||||||
netServer # EE.on_ listeningH onStarted
|
liftEffect $ EE.on_ listeningH (launchAff_ $ performM onStarted) netServer
|
||||||
listenTcp netServer options
|
liftEffect $ listenTcp netServer options
|
||||||
let closingHandler = NServer.close netServer
|
let closingHandler = NServer.close netServer
|
||||||
liftEffect $ registerClosingHandler filledOptions.closingHandler (\eff -> eff *> closingHandler)
|
srv <- registerClosingHandler filledOptions.closingHandler (\eff -> eff *> closingHandler)
|
||||||
|
liftEffect srv
|
||||||
|
|
||||||
serve ::
|
serve ::
|
||||||
forall route from fromRL via missing missingList.
|
forall route from fromRL via missing missingList.
|
||||||
RowToList missing missingList =>
|
RowToList missing missingList =>
|
||||||
FillableFields missingList () missing =>
|
FillableFields missingList () missing =>
|
||||||
Union via missing (ListenOptionsR) =>
|
Union via missing (ListenOptionsR Aff) =>
|
||||||
RowToList from fromRL =>
|
RowToList from fromRL =>
|
||||||
JustifiableFields fromRL from () via =>
|
JustifiableFields fromRL from () via =>
|
||||||
{ | from } ->
|
{ | from } ->
|
||||||
BasicRoutingSettings route ->
|
BasicRoutingSettings Aff route ->
|
||||||
ServerM
|
ServerM
|
||||||
serve inputOptions { route, router } = do
|
serve inputOptions { route, router } = do
|
||||||
let
|
let
|
||||||
extendedSettings = { route, router: asExtended router }
|
extendedSettings = { route, router: asExtended router }
|
||||||
|
serveInternal identity inputOptions Nothing extendedSettings
|
||||||
|
|
||||||
serveInternal inputOptions Nothing extendedSettings
|
serve' ::
|
||||||
|
forall m route from fromRL via missing missingList.
|
||||||
|
MonadAff m =>
|
||||||
|
MonadError Error m =>
|
||||||
|
RowToList missing missingList =>
|
||||||
|
FillableFields missingList () missing =>
|
||||||
|
Union via missing (ListenOptionsR m) =>
|
||||||
|
RowToList from fromRL =>
|
||||||
|
JustifiableFields fromRL from () via =>
|
||||||
|
(m Unit -> Aff Unit) ->
|
||||||
|
{ | from } ->
|
||||||
|
BasicRoutingSettings m route ->
|
||||||
|
ServerM
|
||||||
|
serve' ma inputOptions { route, router } = do
|
||||||
|
let
|
||||||
|
extendedSettings = { route, router: asExtended router }
|
||||||
|
serveInternal ma inputOptions Nothing extendedSettings
|
||||||
|
|
||||||
serveNodeMiddleware ::
|
serveNodeMiddleware ::
|
||||||
forall route from fromRL via missing missingList input output outputRL thru.
|
forall route from fromRL via missing missingList input output outputRL thru.
|
||||||
RowToList missing missingList =>
|
RowToList missing missingList =>
|
||||||
FillableFields missingList () missing =>
|
FillableFields missingList () missing =>
|
||||||
Union via missing (ListenOptionsR) =>
|
Union via missing (ListenOptionsR Aff) =>
|
||||||
RowToList from fromRL =>
|
RowToList from fromRL =>
|
||||||
JustifiableFields fromRL from () via =>
|
JustifiableFields fromRL from () via =>
|
||||||
Union output thru output =>
|
Union output thru output =>
|
||||||
@ -274,17 +306,17 @@ serveNodeMiddleware ::
|
|||||||
KeysRL outputRL =>
|
KeysRL outputRL =>
|
||||||
Nub (RequestR route output) (RequestR route output) =>
|
Nub (RequestR route output) (RequestR route output) =>
|
||||||
{ | from } ->
|
{ | from } ->
|
||||||
ExtRoutingSettings route input output ->
|
ExtRoutingSettings Aff route input output ->
|
||||||
ServerM
|
ServerM
|
||||||
serveNodeMiddleware inputOptions { route, router, nodeMiddleware } = do
|
serveNodeMiddleware inputOptions { route, router, nodeMiddleware } = do
|
||||||
let
|
let
|
||||||
extendedSettings = { route, router: asExtended router }
|
extendedSettings = { route, router: asExtended router }
|
||||||
|
|
||||||
serveInternal inputOptions (Just nodeMiddleware) extendedSettings
|
serveInternal identity inputOptions (Just nodeMiddleware) extendedSettings
|
||||||
|
|
||||||
registerClosingHandler :: Maybe ClosingHandler -> (Effect Unit -> Effect Unit) -> ServerM
|
registerClosingHandler :: forall m. MonadEffect m => Maybe ClosingHandler -> (Effect Unit -> Effect Unit) -> m ServerM
|
||||||
registerClosingHandler (Just NoClosingHandler) closingHandler = pure closingHandler
|
registerClosingHandler (Just NoClosingHandler) closingHandler = pure $ pure closingHandler
|
||||||
registerClosingHandler _ closingHandler = do
|
registerClosingHandler _ closingHandler = pure $ liftEffect do
|
||||||
Process.process # EE.on_ (mkSignalH SIGINT) (closingHandler $ log "Aye, stopping service now. Goodbye!")
|
Process.process # EE.on_ (mkSignalH SIGINT) (closingHandler $ log "Aye, stopping service now. Goodbye!")
|
||||||
Process.process # EE.on_ (mkSignalH SIGTERM) (closingHandler $ log "Arrgghh I got stabbed in the back 🗡 ... good...bye...")
|
Process.process # EE.on_ (mkSignalH SIGTERM) (closingHandler $ log "Arrgghh I got stabbed in the back 🗡 ... good...bye...")
|
||||||
pure closingHandler
|
pure closingHandler
|
||||||
@ -295,5 +327,5 @@ defaultHostname = "0.0.0.0"
|
|||||||
defaultPort :: Int
|
defaultPort :: Int
|
||||||
defaultPort = 8080
|
defaultPort = 8080
|
||||||
|
|
||||||
defaultOnStart :: String -> Int -> Effect Unit
|
defaultOnStart :: forall m. MonadEffect m => String -> Int -> m Unit
|
||||||
defaultOnStart hostname port = log $ "HTTPurple 🪁 up and running on http://" <> hostname <> ":" <> show port
|
defaultOnStart hostname port = liftEffect $ log $ "HTTPurple 🪁 up and running on http://" <> hostname <> ":" <> show port
|
||||||
|
Loading…
Reference in New Issue
Block a user