{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE TupleSections #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE DeriveDataTypeable #-} -- | -- Module: Aws.Sns.Commands.Publish -- Copyright: Copyright © 2014 AlephCloud Systems, Inc. -- License: MIT -- Maintainer: Lars Kuhtz -- Stability: experimental -- -- /API Version: 2013-03-31/ -- -- Sends a message to all of a topic's subscribed endpoints. When a messageId -- is returned, the message has been saved and Amazon SNS will attempt to -- deliver it to the topic's subscribers shortly. The format of the outgoing -- message to each subscribed endpoint depends on the notification protocol -- selected. -- -- To use the Publish action for sending a message to a mobile endpoint, such -- as an app on a Kindle device or mobile phone, you must specify the -- EndpointArn. The EndpointArn is returned when making a call with the -- CreatePlatformEndpoint action. The second example below shows a request and -- response for publishing to a mobile endpoint. -- -- -- module Aws.Sns.Commands.Publish ( SnsMessage(..) , MessageId(..) , snsMessage , SqsNotification(..) , Publish(..) , PublishResponse(..) , PublishErrors(..) ) where import Aws.Core import Aws.General import Aws.Sns.Core import Aws.Sns.Internal import Control.Applicative import Data.Aeson (ToJSON(..), FromJSON(..), (.:), withObject, encode) import qualified Data.ByteString.Lazy as LB import qualified Data.Map as M import Data.Monoid import Data.String import qualified Data.Text as T import qualified Data.Text.Encoding as T import Data.Time.Clock import Data.Typeable import qualified Network.HTTP.Types as HTTP import Text.XML.Cursor (($//), (&/)) import qualified Text.XML.Cursor as CU publishAction :: SnsAction publishAction = SnsActionPublish -- -------------------------------------------------------------------------- -- -- SNS Messages data SnsMessage = SnsMessage { snsMessageDefault :: !T.Text , snsMessageMap :: !(M.Map SnsProtocol T.Text) } deriving (Show, Read, Eq, Ord, Typeable) snsMessageParameters :: SnsMessage -> (Method, HTTP.QueryText) snsMessageParameters SnsMessage{..} = if M.null snsMessageMap then (Get,) [ ("Message", Just snsMessageDefault) ] else (PostQuery,) [ ("MessageStructure", Just "json") , ("Message", (Just . T.decodeUtf8 . LB.toStrict) msg) ] where msg = encode . M.insert "default" snsMessageDefault . M.mapKeys (toText :: SnsProtocol -> String) $ snsMessageMap snsMessage :: T.Text -> SnsMessage snsMessage t = SnsMessage t M.empty -- | Unique identifier assigned to a published message. -- -- Length Constraint: Maximum 100 characters -- newtype MessageId = MessageId { messageIdText :: T.Text } deriving (Show, Read, Eq, Ord, Monoid, IsString, Typeable, FromJSON, ToJSON) -- -------------------------------------------------------------------------- -- -- SQS Notification Message -- | The format of messages used with 'SnsProtocolSqs' -- -- The format is described informally at -- -- -- data SqsNotification = SqsNotification { sqsNotificationMessageId :: !MessageId , sqsNotificationTopicArn :: !Arn , sqsNotificationSubject :: !(Maybe T.Text) , sqsNotificationMessage :: !T.Text , sqsNotificationTimestamp :: !UTCTime , sqsNotificationSignatureVersion :: !T.Text , sqsNotificationSignature :: !T.Text , sqsNotificationSigningCertURL :: !T.Text , sqsNotificationUnsubscribeURL :: !T.Text } deriving (Show, Read, Eq, Ord, Typeable) instance FromJSON SqsNotification where parseJSON = withObject "SqsNotification" $ \o -> SqsNotification <$> o .: "MessageId" <*> o .: "TopicArn" <*> o .: "Subject" <*> o .: "Message" <*> o .: "Timestamp" <*> o .: "SignatureVersion" <*> o .: "Signature" <*> o .: "SigningCertURL" <*> o .: "UnsubscribeURL" <* (o .: "Type" >>= expectValue ("Notification" :: T.Text)) -- -------------------------------------------------------------------------- -- -- Publish data Publish = Publish { publishMessage :: !SnsMessage -- ^ The message you want to send to the topic. -- -- If you want to send the same message to all transport protocols, include -- the text of the message as a String value. -- -- If you want to send different messages for each transport protocol add -- these to the 'snsMessageMap' map. -- -- Constraints: Messages must be UTF-8 encoded strings at most 256 KB in -- size (262144 bytes, not 262144 characters). -- , publishMessageAttributes_entry_N :: Maybe () -- TODO what's that? -- ^ Message attributes for Publish action. , publishSubject :: !(Maybe T.Text) -- ^ Optional parameter to be used as the "Subject" line when the message -- is delivered to email endpoints. This field will also be included, if -- present, in the standard JSON messages delivered to other endpoints. -- -- Constraints: Subjects must be ASCII text that begins with a letter, -- number, or punctuation mark; must not include line breaks or control -- characters; and must be less than 100 characters long. -- , publishArn :: !(Either Arn Arn) -- ^ Either TopicArn (left) or EndpointArn (right). } deriving (Show, Read, Eq, Ord, Typeable) data PublishResponse = PublishResponse { publishMessageId :: !MessageId -- ^ Unique identifier assigned to the published message. } deriving (Show, Read, Eq, Ord, Typeable) instance ResponseConsumer r PublishResponse where type ResponseMetadata PublishResponse = SnsMetadata responseConsumer _ = snsXmlResponseConsumer p where p el = PublishResponse . MessageId <$> arn el arn el = force "Missing Message Id" $ el $// CU.laxElement "PublishResult" &/ CU.laxElement "MessageId" &/ CU.content instance SignQuery Publish where type ServiceConfiguration Publish = SnsConfiguration signQuery Publish{..} = snsSignQuery SnsQuery { snsQueryMethod = method , snsQueryAction = publishAction , snsQueryParameters = msgQuery <> subject <> arn <> entry , snsQueryBody = Nothing } where (method, msgQuery) = snsMessageParameters publishMessage subject = maybe [] (\x -> [("Subject", Just x)]) publishSubject arn = case publishArn of Left a -> [("TopicArn", Just $ toText a)] Right a -> [("TargetArn", Just $ toText a)] entry = [] -- TODO instance Transaction Publish PublishResponse instance AsMemoryResponse PublishResponse where type MemoryResponse PublishResponse = PublishResponse loadToMemory = return -- -------------------------------------------------------------------------- -- -- Errors -- -- Currently not used for requests. It's included for future usage -- and as reference. data PublishErrors = PublishAuthorizationError -- ^ Indicates that the user has been denied access to the requested resource. -- -- /Code 403/ | PublishInternalError -- ^ Indicates an internal service error. -- -- /Code 500/ | PublishInvalidParameter -- ^ Indicates that a request parameter does not comply with the associated constraints. -- -- /Code 400/ | PublishEndpointDisabled -- ^ Exception error indicating endpoint disabled. -- -- /Code 400/ | PublishInvalidParameterValue -- ^ Indicates that a request parameter does not comply with the associated constraints. -- -- /Code 400/ | PublishNotFound -- ^ Indicates that the requested resource does not exist. -- -- /Code 404/ | PublishApplicationDisabled -- ^ Exception error indicating platform application disabled. -- -- /Code 400/ deriving (Show, Read, Eq, Ord, Enum, Bounded, Typeable)