weather-api (empty) → 0.0
raw patch · 5 files changed
+196/−0 lines, 5 filesdep +HTTPdep +basedep +hxtsetup-changed
Dependencies added: HTTP, base, hxt, network, resource-pool
Files
- LICENSE +20/−0
- Setup.hs +2/−0
- WeatherApi.hs +79/−0
- WeatherApi/Google.hs +68/−0
- weather-api.cabal +27/−0
+ LICENSE view
@@ -0,0 +1,20 @@+Copyright (c) 2012 Formal Methods+Copyright (c) 2012 Tim, Max++Permission is hereby granted, free of charge, to any person obtaining a copy of+this software and associated documentation files (the "Software"), to deal in+the Software without restriction, including without limitation the rights to+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies+of the Software, and to permit persons to whom the Software is furnished to do+so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in all+copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+SOFTWARE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ WeatherApi.hs view
@@ -0,0 +1,79 @@+-- | Usage:+--+-- required imports+--+-- > import WeatherApi+-- > import WeatherApi.Google+--+-- With handler in case server will alow you to make+-- few requests with one connection+--+-- >>> let h = mkWeatherHandler $ initApi "en" "utf-8"+-- >>> getWeather h "moscow"+-- Right (Weather { tempF = 75.0+-- , tempC = 24.0+-- , humidity = "Humidity: 25%"+-- , windCondition = "Wind: S at 16 mph"+-- , condition = "Clear"+-- })+--+-- Simple case+--+-- >>> getWeather' (initApi "en" "utf-8") "moscow"+-- Right (Weather { tempF = 75.0+-- , tempC = 24.0+-- , humidity = "Humidity: 25%"+-- , windCondition = "Wind: S at 16 mph"+-- , condition = "Clear"+-- })++module WeatherApi (WeatherApiHandler(..)+ ,Config(..)+ ,Weather(..)+ ,getWeather+ ,getWeather'+ ,mkWeatherHandler+ ,isHandlerAlive+ ,closeHandler) where++import Network.HTTP+import Network.URI++data Config = Config { apiHost :: String+ , apiPort :: Int+ , queryFun :: HandleStream String ->+ String ->+ IO (Either String Weather)+ }++data WeatherApiHandler = WeatherApiHandler+ { stream :: IO (HandleStream String)+ , config :: Config+ }++data Weather = Weather { tempF, tempC :: Double+ , humidity :: String+ , windCondition :: String+ , condition :: String+ } deriving (Eq, Show)++mkWeatherHandler c@(Config apiHost apiPort queryFun) =+ WeatherApiHandler { stream = openStream apiHost apiPort+ , config = c+ }++isHandlerAlive (WeatherApiHandler stream (Config h p _)) =+ stream >>= \s -> isTCPConnectedTo s (EndPoint h p)++closeHandler (WeatherApiHandler stream _) = stream >>= closeQuick++-- | Retrieve weather using existing handler+getWeather (WeatherApiHandler stream c) city =+ stream >>= \s -> queryFun c s city++-- | Retrieve weather using just config+-- It's usefull when you don't need one connection for few requests+getWeather' (Config apiHost apiPort queryFun) city =+ openStream apiHost apiPort >>= \s -> queryFun s city++
+ WeatherApi/Google.hs view
@@ -0,0 +1,68 @@+{-# LANGUAGE Arrows, NoMonomorphismRestriction #-}+module WeatherApi.Google (initApi) where++import Text.XML.HXT.Core+import Network.HTTP+import Network.URI+import WeatherApi+import Control.Monad (liftM)+apiUrl = "http://www.google.com/ig/api?"++type Lang = String+type Enc = String++-- | Make config for use with WeatherApi functions+initApi :: Lang -> Enc -> Config+initApi lang enc =+ let params = [("hl", lang), ("oe", enc)]+ urn c = urlEncodeVars $ params ++ [("weather", c)]+ in Config { apiHost = "www.google.com"+ , apiPort = 80+ , queryFun = makeQueryFun urn+ }++retrieve s urn =+ case parseURI $ apiUrl ++ urn of+ Nothing -> return $ Left "Invalid URL"+ Just uri -> get s uri++get s uri =+ do+ eresp <- sendHTTP s (Request uri GET [] "")+ case eresp of+ Left err -> return $ Left $ show err+ Right res -> return $ Right $ rspBody res++atTag tag = deep (isElem >>> hasName tag)+dataAtTag tag = atTag tag >>> getAttrValue "data"++parseWeather = atTag "current_conditions" >>>+ proc x -> do+ tempF' <- dataAtTag "temp_f" -< x+ tempC' <- dataAtTag "temp_c" -< x+ humidity' <- dataAtTag "humidity" -< x+ windCondition' <- dataAtTag "wind_condition" -< x+ condition' <- dataAtTag "condition" -< x+ returnA -< Weather+ { tempF = read tempF'+ , tempC = read tempC'+ , humidity = humidity'+ , windCondition = windCondition'+ , condition = condition'+ }++parseXML = readString [ withValidate no+ , withRemoveWS yes+ ]++-- | This return function witch will actualy retrieve and parse weather from stream+makeQueryFun q stream city =+ do+ resp <- retrieve stream $ q city+ case liftM parseXML resp of+ Left a -> return $ Left a+ Right a -> do+ r <- runX(a >>> parseWeather)+ case r of+ [] -> return $ Left "can't retrieve weather"+ (x:xs) -> return $ Right x
+ weather-api.cabal view
@@ -0,0 +1,27 @@+Name: weather-api+Version: 0.0+Synopsis: Weather api implemented in haskell+Description:+ This library implement generic api for retrieving weather+ by http, and has google weather api as example.++Homepage: https://github.com/cvb/hs-weather-api.git+License: MIT+License-file: LICENSE+Author: Peter+Maintainer: peter@standalone.su+Build-type: Simple+Category: API++Cabal-version: >= 1.6+Library+ Exposed-modules: WeatherApi, WeatherApi.Google+ Build-depends: base == 4.*+ ,network == 2.3.*+ ,hxt == 9.2.*+ ,HTTP == 4000.2.*+ ,resource-pool == 0.2.1.*++source-repository head+ type: git+ location: git://github.com/cvb/hs-weather-api.git