pusher-haskell-0.1.0.0: src/Network/Pusher/Channel.hs
-----------------------------------------------------------------------------
-- |
-- Module : Network.Pusher.Channel
-- Copyright : See LICENSE file
-- License : BSD
--
-- Maintainer : Sid Raval <sidsraval@gmail.com>
-- Stability : experimental
-- Portability : non-portable (not tested)
--
-- The 'Network.Pusher.Channel' module provides an simple interface for interacting
-- with Pusher.com's @channel@ endpoints. In particular, one can fetch info
-- about every occupied channel for a given App ID, or more detailed information
-- about a channel specified by name.
-----------------------------------------------------------------------------
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE FlexibleInstances #-}
module Network.Pusher.Channel (getChannelInfo) where
import Network.HTTP
import Control.Applicative
import Control.Monad
import Control.Monad.Reader
import Data.Aeson
import Data.Digest.Pure.SHA
import qualified Data.ByteString.Lazy.Char8 as B
import Data.Hash.MD5
import Data.List
import Network.Pusher.Base
type Environment = (Pusher, Channel, [Info])
-- | @getChannelInfo (pusher, channel, info)@ requests information about a
-- particular channel for the given 'Pusher' instance. The result is either an
-- error message returned by the Pusher server, or a 'ChannelInfo' data
-- structure.
getChannelInfo :: (Pusher, Channel, [Info]) -> IO (Either String ChannelInfo)
getChannelInfo = runReaderT channelInfo
channelInfo :: ReaderT Environment IO (Either String ChannelInfo)
channelInfo = do
(p, c, is) <- ask
response <- liftIO . simpleHTTP . getRequest =<< generateUrl
body <- liftIO $ getResponseBody response
case (decode . B.pack $ body) of
(Just c) -> return $ Right c
Nothing -> return $ Left body
generateUrl :: ReaderT Environment IO String
generateUrl = do
let timestamp = authTimestamp
(p, c, is) <- ask
withoutSignature <- urlWithoutSignature timestamp
(++) (withoutSignature ++ "&auth_signature=")
<$> signedAuthString timestamp
urlWithoutSignature :: Timestamp -> ReaderT Environment IO String
urlWithoutSignature t = do
(p@(Pusher _ k _), c, is) <- ask
liftIO $ ((++) (baseUrl p
++ "/channels/"
++ c
++ "?auth_version=1.0"
++ "&auth_key="
++ k
++ queryParamFromInfo is
++ "&auth_timestamp=")) <$> t
signedAuthString :: Timestamp -> ReaderT Environment IO String
signedAuthString t = do
(p@(Pusher _ _ appSecret), c, is) <- ask
signatureString <- unsignedAuthString t >>= return . B.pack
return . showDigest $ hmacSha256 (B.pack appSecret) signatureString
unsignedAuthString :: Timestamp -> ReaderT Environment IO String
unsignedAuthString t = do
(p@(Pusher appId appKey _), c, is) <- ask
liftIO $ idKeyAndTimestamp appId appKey c
<$> t
>>= (\u -> return $ u ++ "&auth_version=1.0" ++ queryParamFromInfo is)
queryParamFromInfo :: [Info] -> String
queryParamFromInfo [] = mzero
queryParamFromInfo xs = "&info=" ++ (intercalate "," $ map show xs)
idKeyAndTimestamp :: String -> String -> Channel -> String -> String
idKeyAndTimestamp i k c t = "GET\n/apps/"
++ i
++ "/channels/"
++ c
++ "\nauth_key="
++ k
++ "&auth_timestamp="
++ t