packages feed

extensible-effects-concurrent-0.24.0: examples/example-1/Main.hs

-- | A complete example for the library
module Main where

import           GHC.Stack
import           Control.Eff
import           Control.Monad
import           Data.Dynamic
import           Control.Eff.Concurrent
import           Control.Eff.Concurrent.Protocol.Server
import qualified Control.Exception             as Exc
import qualified Data.Text as T
import           Control.DeepSeq
import           Data.Type.Pretty

data TestProtocol
  deriving Typeable

type instance ToPretty TestProtocol = PutStr "test"

data instance Pdu TestProtocol x where
  SayHello :: String -> Pdu TestProtocol ('Synchronous Bool)
  Shout :: String -> Pdu TestProtocol 'Asynchronous
  Terminate :: Pdu TestProtocol ('Synchronous ())
  TerminateError :: String -> Pdu TestProtocol ('Synchronous ())
  deriving (Typeable)

instance NFData (Pdu TestProtocol x) where
  rnf (SayHello s) = rnf s
  rnf (Shout s) = rnf s
  rnf Terminate = ()
  rnf (TerminateError s) = rnf s


data MyException = MyException
    deriving Show

instance Exc.Exception MyException

deriving instance Show (Pdu TestProtocol x)

main :: IO ()
main = defaultMain example

mainProcessSpawnsAChildAndReturns :: HasCallStack => Eff InterruptableProcEff ()
mainProcessSpawnsAChildAndReturns = void (spawn (void receiveAnyMessage))

example:: HasCallStack => Eff InterruptableProcEff ()
example = do
  me <- self
  logInfo (T.pack ("I am " ++ show me))
  server <- testServerLoop
  logInfo (T.pack ("Started server " ++ show server))
  let go = do
        lift (putStr "Enter something: ")
        x <- lift getLine
        case x of
          ('K' : rest) -> do
            call server (TerminateError rest)
            go
          ('S' : _) -> do
            call server Terminate
            go
          ('C' : _) -> do
            cast server (Shout x)
            go
          ('R' : rest) -> do
            replicateM_ (read rest) (cast server (Shout x))
            go
          ('q' : _) -> logInfo "Done."
          _         -> do
            res <- call server (SayHello x)
            logInfo (T.pack ("Result: " ++ show res))
            go
  go

type instance GenServerProtocol TestProtocol = TestProtocol

testServerLoop :: Eff InterruptableProcEff (Endpoint TestProtocol)
testServerLoop = start (statelessGenServer handleReq "test-server-1")
 where
  handleReq :: GenServerId TestProtocol -> Event TestProtocol -> Eff (ToStatelessEffects InterruptableProcEff) ()
  handleReq _myId (OnRequest (Call orig Terminate)) = do
    me <- self
    logInfo (T.pack (show me ++ " exiting"))
    sendReply orig ()
    interrupt NormalExitRequested

  handleReq _myId (OnRequest (Call orig (TerminateError e))) = do
    me <- self
    logInfo (T.pack (show me ++ " exiting with error: " ++ e))
    sendReply orig ()
    interrupt (ErrorInterrupt e)

  handleReq _myId (OnRequest (Call orig (SayHello mx))) =
    case mx of
      "e1" -> do
        me <- self
        logInfo (T.pack (show me ++ " raising an error"))
        interrupt (ErrorInterrupt "No body loves me... :,(")

      "e2" -> do
        me <- self
        logInfo (T.pack (show me ++ " throwing a MyException "))
        void (lift (Exc.throw MyException))

      "self" -> do
        me <- self
        logInfo (T.pack (show me ++ " casting to self"))
        cast (asEndpoint @TestProtocol me) (Shout "from me")
        sendReply orig False

      "stop" -> do
        me <- self
        logInfo (T.pack (show me ++ " stopping me"))
        sendReply orig False
        interrupt (ErrorInterrupt "test error")

      x -> do
        me <- self
        logInfo (T.pack (show me ++ " Got Hello: " ++ x))
        sendReply orig (length x > 3)

  handleReq _myId (OnRequest (Cast (Shout x))) = do
    me <- self
    logInfo (T.pack (show me ++ " Shouting: " ++ x))

  handleReq _myId (OnInterrupt msg) = do
    me <- self
    logInfo (T.pack (show me ++ " is exiting: " ++ show msg))
    logProcessExit msg
    interrupt msg

  handleReq _myId wtf = do
    me <- self
    logCritical (T.pack (show me ++ " WTF: " ++ show wtf))