battlenet (empty) → 0.1.0.0
raw patch · 8 files changed
+294/−0 lines, 8 filesdep +aesondep +basedep +containerssetup-changed
Dependencies added: aeson, base, containers, http-conduit, text
Files
- BattleNet.hs +6/−0
- BattleNet/ApiKey.hs +9/−0
- BattleNet/Plumbing.hs +37/−0
- BattleNet/WoW.hs +76/−0
- BattleNet/WoWStatic.hs +70/−0
- LICENSE +20/−0
- Setup.hs +2/−0
- battlenet.cabal +74/−0
+ BattleNet.hs view
@@ -0,0 +1,6 @@+module BattleNet(module BattleNet) where++import BattleNet.ApiKey as BattleNet+import BattleNet.WoWStatic as BattleNet+import BattleNet.WoW as BattleNet+
+ BattleNet/ApiKey.hs view
@@ -0,0 +1,9 @@+module BattleNet.ApiKey(BattleNetApiKey(..)) where++import Data.Text++data BattleNetApiKey = BattleNetApiKey+ { bnetApiKey :: Text+ , bnetApiSecret :: Text+ , bnetRegion :: Text+ }
+ BattleNet/Plumbing.hs view
@@ -0,0 +1,37 @@+module BattleNet.Plumbing where++import BattleNet.ApiKey++import Control.Applicative+import Control.Monad+import Data.Monoid+import Data.Maybe+import Data.List+import Data.Text hiding (intersperse)+import Data.Aeson+import qualified Data.Aeson as Aeson+import Network.HTTP.Conduit hiding (path, queryString)++apiEndpointUrl' :: Text -> BattleNetApiKey -> [Text] -> [(Text, Text)] -> Text+apiEndpointUrl' baseDomain key parts queryString = Data.Text.concat $ mconcat+ [ ["https://"+ , bnetRegion key+ , "."+ , baseDomain+ , "/"]+ , renderedParts parts+ , "?" : renderedQueryStringParams queryString+ ]+ where renderedParts = Data.List.intersperse "/"+ renderedQueryStringParam (k, v) = [k, "=", v]+ renderedQueryStringParams = mconcat . intersperse ["&"] . fmap renderedQueryStringParam++apiEndpointUrl :: [Text] -> [(Text, Text)] -> BattleNetApiKey -> Text+apiEndpointUrl parts queryString key = apiEndpointUrl' "api.battle.net" key parts (("apikey", bnetApiKey key) : queryString)++apiEndpoint :: FromJSON a => [Text] -> [(Text, Text)] -> Manager -> BattleNetApiKey -> IO a+apiEndpoint parts queryString manager key = do+ path <- parseUrl $ unpack $ apiEndpointUrl parts queryString key+ response <- responseBody <$> httpLbs path manager+ let decoded = Aeson.decode response+ return $ fromMaybe (error $ mconcat ["Invalid response from ", show path, ": ", show response]) decoded
+ BattleNet/WoW.hs view
@@ -0,0 +1,76 @@+module BattleNet.WoW(WoWCharacterInfo(..), WoWGuildMemberInfo(..), character, userCharacters, guildMembers) where++import BattleNet.ApiKey+import BattleNet.Plumbing+import BattleNet.WoWStatic+import Data.Aeson+import Data.Map+import Data.Text+import Control.Applicative+import Control.Monad+import Network.HTTP.Conduit++data WoWCharacterInfo = WoWCharacterInfo+ { characterName :: Text+ , characterRealm :: Text+ , characterClass :: WoWClassInfoId+ , characterThumbnail :: Text+ , characterLevel :: Int+ } deriving Show++instance FromJSON WoWCharacterInfo where+ parseJSON (Object v) = do+ characterName <- v .: "name"+ characterRealm <- v .: "realm"+ characterClass <- WoWClassInfoId <$> v .: "class"+ characterThumbnail <- v .: "thumbnail"+ characterLevel <- v .: "level"+ return WoWCharacterInfo+ { characterName = characterName+ , characterRealm = characterRealm+ , characterClass = characterClass+ , characterThumbnail = characterThumbnail+ , characterLevel = characterLevel+ }+ parseJSON _ = mzero++newtype UserCharactersWrapper = UserCharactersWrapper [WoWCharacterInfo]++instance FromJSON UserCharactersWrapper where+ parseJSON (Object v) = UserCharactersWrapper <$> v .: "characters"+ parseJSON _ = mzero++data WoWGuildMemberInfo = WoWGuildMemberInfo+ { memberName :: Text+ , memberRealm :: Text+ , memberRank :: Int+ }++instance FromJSON WoWGuildMemberInfo where+ parseJSON (Object v) = do+ member <- v .: "character"+ memberName <- member .: "name"+ memberRealm <- member .: "realm"+ memberRank <- v .: "rank"+ return WoWGuildMemberInfo+ { memberName = memberName+ , memberRealm = memberRealm+ , memberRank = memberRank+ }++newtype GuildMemberWrapper = GuildMemberWrapper [WoWGuildMemberInfo]++instance FromJSON GuildMemberWrapper where+ parseJSON (Object v) = GuildMemberWrapper <$> v .: "members"+ parseJSON _ = mzero++character :: Text -> Text -> Manager -> BattleNetApiKey -> IO WoWCharacterInfo+character realm name = apiEndpoint ["wow", "character", realm, name] []++userCharacters :: Text -> Manager -> BattleNetApiKey -> IO [WoWCharacterInfo]+userCharacters accessToken manager key = unwrapChars <$> apiEndpoint ["wow", "user", "characters"] [("access_token", accessToken)] manager key+ where unwrapChars (UserCharactersWrapper chars) = chars++guildMembers :: Text -> Text -> Manager -> BattleNetApiKey -> IO [WoWGuildMemberInfo]+guildMembers realm name manager key = unwrapMembers <$> apiEndpoint ["wow", "guild", realm, name] [("fields", "members")] manager key+ where unwrapMembers (GuildMemberWrapper chars) = chars
+ BattleNet/WoWStatic.hs view
@@ -0,0 +1,70 @@+module BattleNet.WoWStatic( WoWClassInfoId(..)+ , WoWClassInfo(..), classes+ , WoWTalentInfo(..), WoWSpecInfo(..), talents+ ) where++import BattleNet.ApiKey+import BattleNet.Plumbing+import Data.Aeson+import Data.Map+import Data.Text+import Control.Applicative+import Control.Monad+import Network.HTTP.Conduit++newtype WoWClassInfoId = WoWClassInfoId Int deriving (Show, Ord, Eq)++data WoWClassInfo = WoWClassInfo+ { classId :: WoWClassInfoId+ , className :: Text+ } deriving Show++newtype WoWClassesInfo = WoWClassesInfo [WoWClassInfo]+extractClassesInfo :: WoWClassesInfo -> [WoWClassInfo]+extractClassesInfo (WoWClassesInfo x) = x++data WoWSpecInfo = WoWSpecInfo+ { specName :: Text+ } deriving Show++data WoWTalentInfo = WoWTalentInfo+ { talentInfoClass :: Text+ , talentInfoSpecs :: [WoWSpecInfo]+ } deriving Show++instance FromJSON WoWClassInfo where+ parseJSON (Object v) = do+ classId <- WoWClassInfoId <$> v .: "id"+ className <- v .: "name"+ return WoWClassInfo+ { classId = classId+ , className = className+ }+ parseJSON _ = mzero++instance FromJSON WoWClassesInfo where+ parseJSON (Object v) = WoWClassesInfo <$> (v .: "classes" >>= parseJSON)+ parseJSON _ = mzero++instance FromJSON WoWSpecInfo where+ parseJSON (Object v) = do+ specName <- v .: "name"+ return WoWSpecInfo+ { specName = specName+ }++instance FromJSON WoWTalentInfo where+ parseJSON (Object v) = do+ talentInfoClass <- v .: "class"+ talentInfoSpecs <- v .: "specs"+ return WoWTalentInfo+ { talentInfoClass = talentInfoClass+ , talentInfoSpecs = talentInfoSpecs+ }+ parseJSON _ = mzero++classes :: Manager -> BattleNetApiKey -> IO [WoWClassInfo]+classes manager key = extractClassesInfo <$> apiEndpoint ["wow", "data", "character", "classes"] [] manager key++talents :: Manager -> BattleNetApiKey -> IO (Map WoWClassInfoId WoWTalentInfo)+talents manager key = mapKeys (WoWClassInfoId . read) <$> apiEndpoint ["wow", "data", "talents"] [] manager key
+ LICENSE view
@@ -0,0 +1,20 @@+Copyright (c) 2014 Teo Klestrup Röijezon++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
+ battlenet.cabal view
@@ -0,0 +1,74 @@+-- Initial battlenet.cabal generated by cabal init. For further +-- documentation, see http://haskell.org/cabal/users-guide/++-- The name of the package.+name: battlenet++-- The package version. See the Haskell package versioning policy (PVP) +-- for standards guiding when and how versions should be incremented.+-- http://www.haskell.org/haskellwiki/Package_versioning_policy+-- PVP summary: +-+------- breaking API changes+-- | | +----- non-breaking API additions+-- | | | +--- code changes with no API change+version: 0.1.0.0++-- A short (one-line) description of the package.+synopsis: API client for Battle.Net++-- A longer description of the package.+-- description: ++-- The license under which the package is released.+license: MIT++-- The file containing the license text.+license-file: LICENSE++-- The package author(s).+author: Teo Klestrup Röijezon++-- An email address to which users can send suggestions, bug reports, and +-- patches.+maintainer: teo@nullable.se++-- A copyright notice.+-- copyright: ++category: Network++build-type: Simple++-- Extra files to be distributed with the package, such as examples or a +-- README.+-- extra-source-files: ++-- Constraint on the version of Cabal needed to build this package.+cabal-version: >=1.10+++library+ -- Modules exported by the library.+ exposed-modules: BattleNet+ BattleNet.ApiKey+ BattleNet.WoW+ BattleNet.WoWStatic+ BattleNet.Plumbing+ + -- Modules included in this library but not exported.+ -- other-modules: + + -- LANGUAGE extensions used by modules in this package.+ default-extensions: OverloadedStrings++ -- Other library packages from which modules are imported.+ build-depends: base >=4.7 && <4.8,+ http-conduit >=2.1.4 && <2.2,+ text >=1.2 && <1.3,+ aeson >=0.7 && <0.9,+ containers >=0.5.5 && <0.6+ -- Directories containing source files.+ -- hs-source-dirs: + + -- Base language which the package is written in.+ default-language: Haskell2010+