-- | Provides a rather raw interface to the websocket events
--   through a real-time Chan
module Discord.Internal.Gateway
  ( DiscordHandleGateway
  , DiscordHandleCache
  , GatewayException(..)
  , Cache(..)
  , startCacheThread
  , startGatewayThread
  , module Discord.Internal.Types
  ) where

import Prelude hiding (log)
import Control.Concurrent.Chan (newChan, dupChan, Chan)
import Control.Concurrent (forkIO, ThreadId, newEmptyMVar, MVar)
import Data.IORef (newIORef)
import qualified Data.Text as T

import Discord.Internal.Types (Auth, Event, GatewaySendable)
import Discord.Internal.Gateway.EventLoop (connectionLoop, DiscordHandleGateway, GatewayException(..))
import Discord.Internal.Gateway.Cache (cacheLoop, Cache(..), DiscordHandleCache)

startCacheThread :: Chan T.Text -> IO (DiscordHandleCache, ThreadId)
startCacheThread :: Chan Text -> IO (DiscordHandleCache, ThreadId)
startCacheThread Chan Text
log = do
  Chan (Either GatewayException Event)
events <- IO (Chan (Either GatewayException Event))
forall a. IO (Chan a)
newChan :: IO (Chan (Either GatewayException Event))
  MVar (Either (Cache, GatewayException) Cache)
cache <- IO (MVar (Either (Cache, GatewayException) Cache))
forall a. IO (MVar a)
newEmptyMVar :: IO (MVar (Either (Cache, GatewayException) Cache))
  ThreadId
tid <- IO () -> IO ThreadId
forkIO (IO () -> IO ThreadId) -> IO () -> IO ThreadId
forall a b. (a -> b) -> a -> b
$ DiscordHandleCache -> Chan Text -> IO ()
cacheLoop (Chan (Either GatewayException Event)
events, MVar (Either (Cache, GatewayException) Cache)
cache) Chan Text
log
  (DiscordHandleCache, ThreadId) -> IO (DiscordHandleCache, ThreadId)
forall (f :: * -> *) a. Applicative f => a -> f a
pure ((Chan (Either GatewayException Event)
events, MVar (Either (Cache, GatewayException) Cache)
cache), ThreadId
tid)

-- | Create a Chan for websockets. This creates a thread that
--   writes all the received Events to the Chan
startGatewayThread :: Auth -> DiscordHandleCache -> Chan T.Text -> IO (DiscordHandleGateway, ThreadId)
startGatewayThread :: Auth
-> DiscordHandleCache
-> Chan Text
-> IO (DiscordHandleGateway, ThreadId)
startGatewayThread Auth
auth (Chan (Either GatewayException Event)
_events, MVar (Either (Cache, GatewayException) Cache)
_) Chan Text
log = do
  Chan (Either GatewayException Event)
events <- Chan (Either GatewayException Event)
-> IO (Chan (Either GatewayException Event))
forall a. Chan a -> IO (Chan a)
dupChan Chan (Either GatewayException Event)
_events
  Chan GatewaySendable
sends <- IO (Chan GatewaySendable)
forall a. IO (Chan a)
newChan
  IORef (Maybe UpdateStatusOpts)
status <- Maybe UpdateStatusOpts -> IO (IORef (Maybe UpdateStatusOpts))
forall a. a -> IO (IORef a)
newIORef Maybe UpdateStatusOpts
forall a. Maybe a
Nothing
  ThreadId
tid <- IO () -> IO ThreadId
forkIO (IO () -> IO ThreadId) -> IO () -> IO ThreadId
forall a b. (a -> b) -> a -> b
$ Auth -> DiscordHandleGateway -> Chan Text -> IO ()
connectionLoop Auth
auth (Chan (Either GatewayException Event)
events, Chan GatewaySendable
sends, IORef (Maybe UpdateStatusOpts)
status) Chan Text
log
  (DiscordHandleGateway, ThreadId)
-> IO (DiscordHandleGateway, ThreadId)
forall (f :: * -> *) a. Applicative f => a -> f a
pure ((Chan (Either GatewayException Event)
events, Chan GatewaySendable
sends, IORef (Maybe UpdateStatusOpts)
status), ThreadId
tid)