packages feed

discord-gateway (empty) → 0.2.2

raw patch · 3 files changed

+172/−0 lines, 3 filesdep +aesondep +basedep +discord-types

Dependencies added: aeson, base, discord-types, hslogger, transformers, url, websockets, wuss

Files

+ LICENSE view
@@ -0,0 +1,20 @@+Copyright (c) 2016 Joshua Koike++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.
+ discord-gateway.cabal view
@@ -0,0 +1,35 @@+name:                discord-gateway+version:             0.2.2+synopsis:            An API wrapper for Discord in Haskell+description:         Provides an api wrapper and framework for writing+                     bots against the Discord <https://discordapp.com/> API.+                     If for some reason hackage/stackage is failing to build+                     documentation, a backup set is hosted at <https://jano017.github.io/Discord.hs/>+homepage:            https://github.com/jano017/Discord.hs+license:             MIT+license-file:        LICENSE+author:              Joshua Koike+maintainer:          jkoike2013@gmail.com+-- copyright:+category:            Network+build-type:          Simple+-- extra-source-files:+cabal-version:       >=1.10++library+  exposed-modules:     Network.Discord.Gateway+  build-depends:       base==4.*+                     , aeson>=1.0 && <1.2+                     , hslogger==1.2.*+                     , transformers==0.5.*+                     , url==2.1.*+                     , websockets==0.10.*+                     , wuss==1.1.*+                     , discord-types+  ghc-options:         -Wall+  hs-source-dirs:      src+  default-language:    Haskell2010++source-repository head+  type : git+  location: https://github.com/jano017/Discord.hs
+ src/Network/Discord/Gateway.hs view
@@ -0,0 +1,117 @@+{-# LANGUAGE TypeFamilies, MultiParamTypeClasses, FlexibleInstances #-}+{-# OPTIONS_HADDOCK prune, not-home #-}+-- | Provides logic code for interacting with the Discord websocket+--   gateway. Reallistically, this is probably lower level than most+--   people will need, and you should use Language.Discord.+module Network.Discord.Gateway where+  import Control.Concurrent (threadDelay)+  import Control.Monad (forever)+  import Control.Monad.IO.Class (liftIO)+  import Data.Maybe (fromJust)++  import Data.Aeson+  import Network.WebSockets hiding (send)+  import Network.URL+  import System.Log.Logger+  import Wuss++  import Network.Discord.Types++  data GatewayState+    = Create+    | Start+    | Running+    | InvalidReconnect+    | InvalidDead++  class DiscordAuth m => DiscordGate m where+    data VaultKey m a+    +    type Vault m :: * -> *+    -- | Retrieve a value from the store, blocking if the store is empty+    get :: Vault m a -> m a+    -- | Place a value into the store, discarding the old value if present.+    put  :: Vault m a -> a -> m ()++    sequenceKey :: VaultKey m Integer+    storeFor :: VaultKey m a -> m ((Vault m) a)++    connection   :: m Connection+    feed :: m () -> Event -> m ()++    run  :: m () -> Connection -> IO ()+    fork :: m () -> m ()++  runGateway :: DiscordGate m => URL -> m () -> IO ()+  runGateway (URL (Absolute h) path _) client =+    runSecureClient (host h) 443 (path ++ "/?v=6")+      $ run client+  runGateway _ _ = return ()++  send :: DiscordGate m => Payload -> m ()+  send payload = do+    conn <- connection+    liftIO . sendTextData conn $ encode payload++  heartbeat :: DiscordGate m => Int -> m ()+  heartbeat interval = fork . forever $ do+    seqNum <- Heartbeat <$> (get =<< storeFor sequenceKey)+    send seqNum+    liftIO $ threadDelay (interval * 1000)++  setSequence :: DiscordGate m => Integer -> m ()+  setSequence sq = do+    seqNum <- storeFor sequenceKey+    put seqNum sq++  eventStream :: DiscordGate m => GatewayState -> m () -> m ()+  eventStream Create m = do+    Hello interval <- step+    heartbeat interval+    eventStream Start m+  eventStream Start m = do+    creds <- auth+    send $ Identify creds False 50 (0, 1)+    eventStream Running m+  eventStream Running m = do+    payload <- step+    case payload of+      Dispatch _ sq _ -> do+        setSequence sq+        case parseDispatch payload of+          Left reason -> liftIO $ errorM "Discord-hs.Gateway.Dispatch" reason+          Right event -> do+            liftIO $ print event+            feed m event+        liftIO $ putStrLn "Stepping app"+        eventStream Running m+      Heartbeat sq -> do+        setSequence sq+        send $ Heartbeat sq+        eventStream Running m+      Reconnect      -> eventStream InvalidReconnect m+      InvalidSession -> eventStream Start m+      HeartbeatAck   -> eventStream Running m+      _              -> do+        liftIO $ errorM "Discord-hs.Gateway.Error" "InvalidPacket"+        liftIO $ putStrLn "DYING RIP ME"+        eventStream InvalidDead m+  eventStream InvalidReconnect m = eventStream InvalidDead m+  eventStream InvalidDead      _ = liftIO $ errorM "Discord-hs.Gateway.Error" "Bot died"++  step :: DiscordGate m => m Payload+  step = do+    conn <- connection+    liftIO $ putStrLn "Waiting for data"+    msg' <- liftIO $ receiveData conn+    liftIO $ putStrLn "Got data"+    case eitherDecode msg' of+      Right msg -> return msg+      Left  err -> +        ( liftIO+          $  errorM "Discord-hs.Gateway.Parse" err+          >> infoM "Discord-hs.Gateway.Raw" (show msg')+        ) >> (return $ ParseError err)+  +  gatewayUrl :: URL+  gatewayUrl = fromJust $ importURL "wss://gateway.discord.gg"