dresdner-verkehrsbetriebe-1.0.0: src/Network/Transportation/Germany/DVB/Monitor.hs
-- |
-- Module: Network.Transportation.Germany.DVB.Monitor
-- Copyright: (C) 2016 Braden Walters
-- License: MIT (see LICENSE file)
-- Maintainer: Braden Walters <vc@braden-walters.info>
-- Stability: experimental
-- Portability: ghc
module Network.Transportation.Germany.DVB.Monitor
( MonitorRequest(..)
, MonitorResult(..)
, TransitConnection(..)
, Error(..)
, monitor
) where
import Data.Aeson
import qualified Data.ByteString.Lazy.Char8 as BS8
import Network.HTTP
import Network.Stream
import Network.Transportation.Germany.DVB
import qualified Network.Transportation.Germany.DVB.Monitor.JSON as JSON
-- |All data sent to DVB to monitor a stop.
data MonitorRequest = MonitorRequest
{ monitorReqCity :: City
, monitorReqStop :: Location
, monitorReqOffset :: Integer
, monitorReqLimit :: Integer
} deriving (Show)
-- |Either monitor data or an error.
type MonitorResult = Either Error [TransitConnection]
-- |An arriving vehicle at the stop.
data TransitConnection = TransitConnection
{ transConnNumber :: String
, transConnDesc :: String
, transConnArrivalMinutes :: Integer
} deriving (Show)
-- |All possible errors which could occur while fetching data, including HTTP
-- errors and JSON parsing errors.
data Error = HttpResetError | HttpClosedError | HttpParseError String |
HttpMiscError String | JsonParseError String deriving (Show)
-- |Given information about a stop, query and return data from DVB about
-- vehicles stopping there.
monitor :: MonitorRequest -> IO MonitorResult
monitor req = do
let (City city) = monitorReqCity req
(Location stop) = monitorReqStop req
params = [("ort", city),
("hst", stop),
("vz", show $ monitorReqOffset req),
("lim", show $ monitorReqLimit req)]
result <- simpleHTTP (getRequest (monitorUrl ++ "?" ++ urlEncodeVars params))
case result of
Left connError -> return $ Left $ connErrToResultErr connError
Right response' ->
let body = BS8.pack $ rspBody response'
in case eitherDecode body of
Left err ->
return $ Left $ JsonParseError err
Right transConns ->
return $ Right (map fromJsonTransitConnection transConns)
-- |The HTTP URL to query for DVB monitor data.
monitorUrl :: String
monitorUrl = "http://widgets.vvo-online.de/abfahrtsmonitor/Abfahrten.do"
-- |Take an HTTP connection error and convert it into an error which can be
-- returned in a RouteResult.
connErrToResultErr :: ConnError -> Error
connErrToResultErr ErrorReset = HttpResetError
connErrToResultErr ErrorClosed = HttpClosedError
connErrToResultErr (ErrorParse msg) = HttpParseError msg
connErrToResultErr (ErrorMisc msg) = HttpMiscError msg
fromJsonTransitConnection :: JSON.TransitConnection -> TransitConnection
fromJsonTransitConnection transConn =
TransitConnection {
transConnNumber = JSON.transConnNumber transConn,
transConnDesc = JSON.transConnDesc transConn,
-- TODO: Use a total function instead of read.
transConnArrivalMinutes = read $ JSON.transConnArrivalMinutes transConn
}