rasa-0.1.4: src/Rasa/Internal/Async.hs
module Rasa.Internal.Async
( doAsync
, eventProvider
) where
import Rasa.Internal.Action
import Rasa.Internal.Scheduler
import Data.Typeable
import Control.Concurrent.Async
import Control.Lens
import Control.Monad.IO.Class
-- | This function takes an IO which results in some Event, it runs the IO
-- asynchronously and dispatches the event, then repeats the process all over
-- again. Use this inside the onInit scheduler to register an event listener
-- for some event (e.g. keypresses or network activity)
eventProvider :: Typeable a => IO a -> Action ()
eventProvider getEventIO = doAsync (dispatchAndRerun <$> getEventIO)
where dispatchAndRerun evt = do
dispatchEvent evt
eventProvider getEventIO
-- | doAsync allows you to perform a task asynchronously and then apply the
-- result. In @doAsync asyncAction@, @asyncAction@ is an IO which resolves to
-- an Action, note that the context in which the second action is executed is
-- NOT the same context in which doAsync is called; it is likely that text and
-- other state have changed while the IO executed, so it's a good idea to check
-- (inside the applying Action) that things are in a good state before making
-- changes. Here's an example:
--
-- > asyncCapitalize :: Action ()
-- > asyncCapitalize = do
-- > txt <- focusDo $ use text
-- > -- We give doAsync an IO which resolves in an action
-- > doAsync $ ioPart txt
-- >
-- > ioPart :: Text -> IO (Action ())
-- > ioPart txt = do
-- > result <- longAsyncronousCapitalizationProgram txt
-- > -- Note that this returns an Action, but it's still wrapped in IO
-- > return $ maybeApplyResult txt result
-- >
-- > maybeApplyResult :: Text -> Text -> Action ()
-- > maybeApplyResult oldTxt capitalized = do
-- > -- We get the current buffer's text, which may have changed since we started
-- > newTxt <- focusDo (use text)
-- > if newTxt == oldTxt
-- > -- If the text is the same as it was, we can apply the transformation
-- > then focusDo (text .= capitalized)
-- > -- Otherwise we can choose to re-queue the whole action and try again
-- > -- Or we could just give up.
-- > else asyncCapitalize
doAsync :: IO (Action ()) -> Action ()
doAsync asyncIO = do
newAsync <- liftIO $ async asyncIO
asyncs <>= [newAsync]