{-# LANGUAGE NoImplicitPrelude #-}
module Data.Aviation.Stratux.Websockets(
WSConnectionIO
, decodeWith
, decode
, decode'
, stratuxApp
, trafficAppWith
, trafficApp
, trafficApp'
) where
import Control.Category(Category((.)))
import Data.Aeson(FromJSON)
import qualified Data.Aeson as A(eitherDecode, eitherDecode')
import Control.Concurrent(forkIO)
import Control.Monad(Monad((>>=), (>>)), forever, unless)
import Control.Monad.Trans.Reader(ReaderT(ReaderT))
import Control.Monad.Trans.Except(ExceptT(ExceptT))
import Data.Aviation.Stratux.Types(Traffic)
import Data.Either(Either)
import Data.Function(($))
import Data.Functor(Functor(fmap))
import Data.Int(Int)
import Data.String(String)
import qualified Data.Text as T(null)
import qualified Data.Text.IO as T(getLine)
import Network.Socket (withSocketsDo)
import qualified Network.WebSockets as WS(Connection, WebSocketsData, ClientApp, receiveData, sendClose, sendTextData, runClient)
import System.IO(IO)
type WSConnectionIO f a =
ReaderT WS.Connection (f IO) a
decodeWith ::
WS.WebSocketsData a =>
(a -> b)
-> (IO b -> m c)
-> ReaderT WS.Connection m c
decodeWith d k =
ReaderT (k . fmap d . WS.receiveData)
decode ::
FromJSON a =>
WSConnectionIO (ExceptT String) a
decode =
decodeWith A.eitherDecode ExceptT
decode' ::
FromJSON a =>
WSConnectionIO (ExceptT String) a
decode' =
decodeWith A.eitherDecode' ExceptT
stratuxApp ::
(WS.WebSocketsData t, WS.WebSocketsData u) =>
(t -> IO b)
-> u
-> WS.ClientApp ()
stratuxApp k s c = do
_ <- forkIO . forever $ WS.receiveData c >>= k
let loop = do line <- T.getLine
unless (T.null line) $ WS.sendTextData c line >> loop
loop
WS.sendClose c s
trafficAppWith ::
(WS.WebSocketsData t, WS.WebSocketsData u) =>
(t -> Either String Traffic)
-> String
-> Int
-> (Either String Traffic -> IO b)
-> u
-> IO ()
trafficAppWith q host port k s =
withSocketsDo $ WS.runClient host port "/traffic" (stratuxApp (k . q) s)
trafficApp ::
WS.WebSocketsData u =>
String
-> Int
-> (Either String Traffic -> IO b)
-> u
-> IO ()
trafficApp =
trafficAppWith A.eitherDecode
trafficApp' ::
WS.WebSocketsData u =>
String
-> Int
-> (Either String Traffic -> IO b)
-> u
-> IO ()
trafficApp' =
trafficAppWith A.eitherDecode'