packages feed

reflex-backend-wai (empty) → 0.1.0.0

raw patch · 7 files changed

+287/−0 lines, 7 filesdep +basedep +containersdep +http-typessetup-changed

Dependencies added: base, containers, http-types, mtl, reflex, reflex-backend-wai, reflex-basic-host, stm, wai, warp

Files

+ ChangeLog.md view
@@ -0,0 +1,5 @@+# Revision history for wai-reflex++## 0.1.0.0  -- YYYY-mm-dd++* First version. Released on an unsuspecting world.
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2017, Dave Laing++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Dave Laing nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ exe/Main.hs view
@@ -0,0 +1,20 @@+{-|+Copyright   : (c) Dave Laing, 2017-2019+License     : BSD3+Maintainer  : dave.laing.80@gmail.com+Stability   : experimental+Portability : non-portable+-}+{-# LANGUAGE OverloadedStrings #-}+module Main (main) where++import Network.Wai (responseLBS)+import Network.HTTP.Types.Status (status200)++import Reflex.Backend.Warp (runAppForever)++main :: IO ()+main =+  runAppForever 8080 $ \eReq -> do+    let eRes = responseLBS status200 [] "Hi" <$ eReq+    pure eRes
+ reflex-backend-wai.cabal view
@@ -0,0 +1,62 @@+name:                reflex-backend-wai+version:             0.1.0.0+synopsis:            Reflex interface to `wai`+description:+  Reflex interface to `wai`.+  .+  A minimal example:+  .+  > {-# LANGUAGE OverloadedStrings #-}+  > module Main where+  >  +  > import Network.Wai (responseLBS)+  > import Network.HTTP.Types.Status (status200)+  >  +  > import Reflex.Backend.Warp (runAppForever)+  >  +  > main :: IO ()+  > main =+  >   runAppForever 8080 $ \eReq -> do+  >     let eRes = responseLBS status200 [] "Hi" <$ eReq+  >     pure eRes++license:             BSD3+license-file:        LICENSE+author:              Dave Laing+maintainer:          dave.laing.80@gmail.com+-- copyright:           +category:            FRP, Web+build-type:          Simple+extra-source-files:  ChangeLog.md+cabal-version:       >=1.10+tested-with:         GHC==8.0.2+                   , GHC==8.2.2+                   , GHC==8.4.3+                   , GHC==8.6.4++library+  exposed-modules:     Reflex.Backend.Wai+                     , Reflex.Backend.Warp+  build-depends:       base       >=4.9    && < 4.13+                     , containers >= 0.5   && < 0.7+                     , mtl        >= 2.2.1 && < 2.3+                     , reflex     >= 0.5   && < 0.6+                     , reflex-basic-host >= 0.1 && < 0.2+                     , stm        >= 2.4.4 && < 2.6+                     , wai        >= 3.2.1 && < 3.3+                     , warp >= 3.2.13 && < 3.3+  hs-source-dirs:      src+  ghc-options:         -Wall+  default-language:    Haskell2010++executable example+  main-is:             Main.hs+  build-depends:       base              >=4.9     && < 4.13+                     , http-types        >= 0.9.1  && < 0.13+                     , reflex            >= 0.5    && < 0.6+                     , wai               >= 3.2.1  && < 3.3+                     , reflex-backend-wai+  hs-source-dirs:      exe+  ghc-options:         -Wall+  default-language:    Haskell2010+  
+ src/Reflex/Backend/Wai.hs view
@@ -0,0 +1,132 @@+{-|+Copyright   : (c) Dave Laing, 2017-2019+License     : BSD3+Maintainer  : dave.laing.80@gmail.com+Stability   : experimental+Portability : non-portable++Low level operations for integrating reflex networks with WAI+'Application's.++If you just want to serve a reflex network then have a look+at "Reflex.Backend.Warp".++-}++{-# LANGUAGE FlexibleContexts #-}+module Reflex.Backend.Wai+  ( WaiSource(..), newWaiSource+  , waiApplicationGuest+  , waiApplicationHost+  , liftWaiApplication, liftWaiApplicationTagged+  )+where++import Network.Wai+import Network.Wai.Internal (ResponseReceived(..))++import Control.Monad (void, forever)++import Control.Monad.Trans (MonadIO, liftIO)++import Data.Map (Map)+import qualified Data.Map as Map++import Control.Concurrent (forkIO)+import Control.Monad.STM+import Control.Concurrent.STM++import Reflex hiding (Request, Response)++-- | The source of the WAI application data.+--+-- Requests generated by the web server are stored here, and read+-- by the reflex network.+--+-- Responses generated by the reflex network are stored here, and+-- read (and subsequently returned) by the web server.+data WaiSource+  = WaiSource+  { wsRequest :: TMVar Request+  , wsResponse :: TMVar Response+  }++-- | Initialise a 'WaiSource'+newWaiSource :: MonadIO m => m WaiSource+newWaiSource =+  liftIO $ WaiSource <$> newEmptyTMVarIO <*> newEmptyTMVarIO++-- | Build an 'Application' that deposits a 'Request' into the+-- 'WaiSource', then reads a 'Response' from the 'WaiSource', then+-- responds with it.+waiApplicationHost :: WaiSource -> Application+waiApplicationHost (WaiSource wReq wRes) req response = do+  atomically $ putTMVar wReq req+  res <- atomically $ takeTMVar wRes+  response res++-- | Build a reflex network that pumps 'Request's and 'Response's to+-- and from the 'WaiSource'+waiApplicationGuest ::+  ( Reflex t+  , MonadIO m+  , PerformEvent t m+  , MonadIO (Performable m)+  , TriggerEvent t m+  ) =>+  WaiSource ->+  (Event t Request -> m (Event t Response)) ->+  m ()+waiApplicationGuest (WaiSource wReq wRes) network = do+  (eReq, onReq) <- newTriggerEvent+  eRes <- network eReq++  performEvent_ $ liftIO . atomically . putTMVar wRes <$> eRes++  void . liftIO . forkIO . forever $ do+    req <- atomically $ takeTMVar wReq+    onReq req++  pure ()++-- | Given a WAI 'Application' and a 'Request' event, create an+-- 'Event' that yield a 'Response' by running the 'Application'.+--+-- The output 'Event' will fire some time after the input 'Event'.+liftWaiApplication ::+  ( Reflex t+  , PerformEvent t m+  , MonadIO (Performable m)+  , TriggerEvent t m+  ) =>+  Application ->+  Event t Request ->+  m (Event t Response)+liftWaiApplication app eReq = do+  (eRes, onRes) <- newTriggerEvent++  let go res = ResponseReceived <$ onRes res++  performEvent_ $ (\req -> void . liftIO $ app req go) <$> eReq++  pure eRes++-- | Similar to 'liftWaiApplication', but the 'Request' event should yield+-- a tag which is then attached to the 'Response'.+liftWaiApplicationTagged ::+  ( Reflex t+  , PerformEvent t m+  , MonadIO (Performable m)+  , TriggerEvent t m+  ) =>+  Application ->+  Event t (tag, Request) ->+  m (Event t (Map tag Response))+liftWaiApplicationTagged app eReq = do+  (eRes, onRes) <- newTriggerEvent++  let go t res = ResponseReceived <$ onRes (Map.singleton t res)++  performEvent_ $ (\(t, req) -> void . liftIO . app req $ go t) <$> eReq++  pure eRes
+ src/Reflex/Backend/Warp.hs view
@@ -0,0 +1,36 @@+{-|+Copyright   : (c) Dave Laing, 2017-2019+License     : BSD3+Maintainer  : dave.laing.80@gmail.com+Stability   : experimental+Portability : non-portable++Serving reflex networks using @warp@.++-}++{-# language FlexibleContexts, TypeFamilies #-}+{-# language RankNTypes #-}+module Reflex.Backend.Warp where++import Reflex hiding (Request, Response)+import Reflex.Host.Basic (BasicGuestConstraints, BasicGuest, basicHostForever)+import Reflex.Backend.Wai++import Control.Concurrent (forkIO)+import Control.Monad (void)+import Network.Wai (Request, Response)+import Network.Wai.Handler.Warp (Port, run)++-- | Serve a reflex network using warp.+runAppForever+  :: Port -- ^ Server port+  -> (forall t m.+      BasicGuestConstraints t m =>+      Event t Request ->+      BasicGuest t m (Event t Response)) -- ^ Reflex network+  -> IO ()+runAppForever port network = do+  waiSource <- newWaiSource+  void . forkIO $ basicHostForever (waiApplicationGuest waiSource network)+  void . run port $ waiApplicationHost waiSource