{-# LANGUAGE TypeFamilies, FlexibleContexts, ConstrainedClassMethods, AllowAmbiguousTypes #-} module Distrib.Butter.Lib.Protocol where import Distrib.Butter.Lang import Control.Concurrent.Forkable (ForkableMonad(..)) import Control.Monad.IO.Class (MonadIO(..)) import Data.Aeson (FromJSON(..), ToJSON(..)) data Result p = Reply p (State p) | NoReply (State p) | Terminate | Restart class (ToJSON p, FromJSON p) => Protocol p where data State p type Context p :: * -> * setup :: (MonadIO (Context p), ForkableMonad (Context p)) => p -> Butter (Context p) (State p) handle :: (MonadIO (Context p), ForkableMonad (Context p)) => p -> State p -> Butter (Context p) (Result p) start :: (MonadIO (Context p), ForkableMonad (Context p), Protocol p) => p -> Butter (Context p) (ProcessID) start p = let server s = do (from,p') <- receive result <- handle p' s case result of Reply p'' s' -> do send from p'' server s' NoReply s' -> server s' Terminate -> return () Restart -> do s' <- setup p' server s' in do s <- setup p spawn $ server s call :: (MonadIO (Context p), ForkableMonad (Context p), Protocol p) => ProcessID -> p -> Butter (Context p) p call to p = do me <- self send to (me,p) receive cast :: (MonadIO (Context p), ForkableMonad (Context p), Protocol p) => ProcessID -> p -> Butter (Context p) () cast to p = do me <- self send to (me,p)