push-notify-apn 0.4.0.2 → 0.4.0.3
raw patch · 4 files changed
+53/−14 lines, 4 filesdep +http-typesdep ~http2
Dependencies added: http-types
Dependency ranges changed: http2
Files
- changelog.md +7/−0
- push-notify-apn.cabal +3/−2
- src/Network/PushNotify/APN.hs +41/−12
- test/Network/PushNotify/APNSpec.hs +2/−0
changelog.md view
@@ -1,3 +1,10 @@+0.4.0.3+=======++- Support http-2-5.3+- Support data-default >= 0.8+- Use empty string instead of undefined in server id+ 0.4.0.2 =======
push-notify-apn.cabal view
@@ -1,5 +1,5 @@ name: push-notify-apn-version: 0.4.0.2+version: 0.4.0.3 synopsis: Send push notifications to mobile iOS devices description: push-notify-apn is a library and command line utility that can be used to send@@ -29,8 +29,9 @@ , bytestring , containers , data-default- , http2 >= 3.0 && <= 5.1+ , http2 >= 3.0 && <= 5.4 , http2-client >= 0.10.0.2+ , http-types >= 0.12.4 , lifted-base , mtl , random
src/Network/PushNotify/APN.hs view
@@ -37,6 +37,8 @@ , clearAlertMessage , clearBadge , clearCategory+ , setMutableContent+ , clearMutableContent , clearSound , addSupplementalField , closeSession@@ -91,6 +93,7 @@ import qualified Network.HPACK as HTTP2 import qualified Network.HTTP2.Frame as HTTP2+import qualified Network.HTTP.Types as HTTP -- | A session that manages connections to Apple's push notification service data ApnSession = ApnSession@@ -138,7 +141,7 @@ -- | Exceptional responses to a send request data ApnException = ApnExceptionHTTP ErrorCode | ApnExceptionJSON String- | ApnExceptionMissingHeader HTTP2.HeaderName+ | ApnExceptionMissingHeader HTTP.HeaderName | ApnExceptionUnexpectedResponse | ApnExceptionConnectionClosed | ApnExceptionSessionClosed@@ -189,11 +192,13 @@ -- in the Library/Sounds directory of the app. , jamCategory :: !(Maybe Text) -- ^ The category of the notification. Must be registered by the app beforehand.+ , jamMutableContent :: !(Maybe Int)+ -- ^ Whether the message has mutable content. } deriving (Generic, Show) -- | Create an empty apn message emptyMessage :: JsonApsMessage-emptyMessage = JsonApsMessage Nothing Nothing Nothing Nothing+emptyMessage = JsonApsMessage Nothing Nothing Nothing Nothing Nothing -- | Set a sound for an APN message setSound@@ -231,6 +236,24 @@ -- ^ The modified message clearCategory a = a { jamCategory = Nothing } +-- | Set the mutable content part of an APN message+setMutableContent+ :: Int+ -- ^ The number of mutable content to set+ -> JsonApsMessage+ -- ^ The message to modify+ -> JsonApsMessage+ -- ^ The modified message+setMutableContent i a = a { jamMutableContent = Just i }++-- | Clear the mutable content part of an APN message+clearMutableContent+ :: JsonApsMessage+ -- ^ The message to modify+ -> JsonApsMessage+ -- ^ The modified message+clearMutableContent a = a { jamMutableContent = Nothing }+ -- | Set the badge part of an APN message setBadge :: Int@@ -305,11 +328,17 @@ instance ToJSON JsonApsMessage where toJSON = genericToJSON defaultOptions- { fieldLabelModifier = drop 3 . map toLower }+ { fieldLabelModifier = \s -> case drop 3 s of+ "MutableContent" -> "mutable-content"+ other -> map toLower other+ } instance FromJSON JsonApsMessage where parseJSON = genericParseJSON defaultOptions- { fieldLabelModifier = drop 3 . map toLower }+ { fieldLabelModifier = \s -> case drop 3 s of+ "mutable-content" -> "MutableContent"+ other -> map toLower other+ } -- | A push notification message data JsonAps@@ -506,16 +535,16 @@ clip <- case (aciUseJWT aci) of True -> do castore <- getSystemCertificateStore- let clip = ClientParams+ let clip = (defaultParamsClient (T.unpack hostname) "") { clientUseMaxFragmentLength=Nothing- , clientServerIdentification=(T.unpack hostname, undefined) , clientUseServerNameIndication=True , clientWantSessionResume=Nothing , clientShared=def { sharedCAStore=castore } , clientHooks=def { onCertificateRequest = const . return $ Nothing }- , clientDebug=DebugParams { debugSeed=Nothing, debugPrintSeed=const $ return (), debugVersionForced=Nothing, debugKeyLogger=const $ return () }+ , clientDebug=def+ { debugSeed=Nothing, debugPrintSeed=const $ return (), debugVersionForced=Nothing, debugKeyLogger=const $ return () } , clientSupported=def { supportedVersions=[ TLS12 ] , supportedCiphers=ciphersuite_strong }@@ -533,15 +562,15 @@ shared = def { sharedCredentials = credentials , sharedCAStore=castore } - clip = ClientParams+ clip = (defaultParamsClient (T.unpack hostname) "") { clientUseMaxFragmentLength=Nothing- , clientServerIdentification=(T.unpack hostname, undefined) , clientUseServerNameIndication=True , clientWantSessionResume=Nothing , clientShared=shared , clientHooks=def { onCertificateRequest=const . return . Just $ credential }- , clientDebug=DebugParams { debugSeed=Nothing, debugPrintSeed=const $ return (), debugVersionForced=Nothing, debugKeyLogger=const $ return () }+ , clientDebug=def+ { debugSeed=Nothing, debugPrintSeed=const $ return (), debugVersionForced=Nothing, debugKeyLogger=const $ return () } , clientSupported=def { supportedVersions=[ TLS12 ] , supportedCiphers=ciphersuite_strong }@@ -710,10 +739,10 @@ eitherDecode body >>= parseEither (\obj -> ctor <$> obj .: "reason") - getHeaderEx :: HTTP2.HeaderName -> [HTTP2.Header] -> HTTP2.HeaderValue+ getHeaderEx :: HTTP.HeaderName -> [HTTP2.Header] -> ByteString getHeaderEx name headers = fromMaybe (throw $ ApnExceptionMissingHeader name) (DL.lookup name headers) - defaultHeaders :: Text -> ByteString -> ByteString -> [(HTTP2.HeaderName, ByteString)]+ defaultHeaders :: Text -> ByteString -> ByteString -> [(HTTP.HeaderName, ByteString)] defaultHeaders hostname token topic = [ ( ":method", "POST" ) , ( ":scheme", "https" ) , ( ":authority", TE.encodeUtf8 hostname )
test/Network/PushNotify/APNSpec.hs view
@@ -16,6 +16,7 @@ "category" .= Null, "sound" .= Null, "badge" .= Null,+ "mutable-content" .= Null, "alert" .= object [ "title" .= String "hello", "body" .= String "world"@@ -27,6 +28,7 @@ "category" .= Null, "sound" .= Null, "badge" .= Null,+ "mutable-content" .= Null, "alert" .= object [ "body" .= String "hello world" ] ]