{-# LANGUAGE CPP #-} {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE NoImplicitPrelude #-} module Data.Morpheus.Subscriptions.WebSockets ( webSocketsWrapper, ) where import Control.Monad.IO.Unlift ( MonadUnliftIO, withRunInIO, ) import Data.Morpheus.Subscriptions.Internal ( ApiContext (..), SUB, Store (..), acceptApolloRequest, ) import Network.WebSockets ( Connection, ServerApp, receiveData, sendTextData, ) import qualified Network.WebSockets as WS import Relude -- support old version of Websockets pingThread :: Connection -> IO () -> IO () #if MIN_VERSION_websockets(0,12,6) pingThread connection = WS.withPingThread connection 30 (return ()) #else pingThread connection = (WS.forkPingThread connection 30 >>) #endif defaultWSScope :: MonadIO m => Store e m -> Connection -> ApiContext SUB e m defaultWSScope Store {writeStore} connection = SubContext { listener = liftIO (receiveData connection), callback = liftIO . sendTextData connection, updateStore = writeStore } webSocketsWrapper :: (MonadUnliftIO m, MonadIO m) => Store e m -> (ApiContext SUB e m -> m ()) -> m ServerApp webSocketsWrapper store handler = withRunInIO $ \runIO -> pure $ \pending -> do conn <- acceptApolloRequest pending pingThread conn $ runIO (handler (defaultWSScope store conn))