-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Message passing concurrency as extensible-effect -- -- Please see the README on GitHub at -- https://github.com/sheyll/extensible-effects-concurrent#readme @package extensible-effects-concurrent @version 0.24.2 -- | Add-ons to Exception and Exception module Control.Eff.ExceptionExtra -- | Catch Exception thrown by an effect. liftTry :: forall e r a. (HasCallStack, Exception e, Lifted IO r) => Eff r a -> Eff r (Either e a) -- | Very similar to liftEither but for Maybes. Unlike -- liftMaybe this will throw the given value (instead of using -- Fail). maybeThrow :: Member (Exc x) e => x -> Maybe a -> Eff e a instance Control.Monad.Catch.MonadThrow (Control.Eff.Internal.Eff e) => Control.Monad.Catch.MonadThrow (Control.Eff.Internal.Eff (Control.Eff.Reader.Lazy.Reader x : e)) instance Control.Monad.Catch.MonadCatch (Control.Eff.Internal.Eff e) => Control.Monad.Catch.MonadCatch (Control.Eff.Internal.Eff (Control.Eff.Reader.Lazy.Reader x : e)) instance Control.Monad.Catch.MonadMask (Control.Eff.Internal.Eff e) => Control.Monad.Catch.MonadMask (Control.Eff.Internal.Eff (Control.Eff.Reader.Lazy.Reader x : e)) instance Control.Monad.Catch.MonadThrow (Control.Eff.Internal.Eff e) => Control.Monad.Catch.MonadThrow (Control.Eff.Internal.Eff (Control.Eff.Reader.Strict.Reader x : e)) instance Control.Monad.Catch.MonadCatch (Control.Eff.Internal.Eff e) => Control.Monad.Catch.MonadCatch (Control.Eff.Internal.Eff (Control.Eff.Reader.Strict.Reader x : e)) instance Control.Monad.Catch.MonadMask (Control.Eff.Internal.Eff e) => Control.Monad.Catch.MonadMask (Control.Eff.Internal.Eff (Control.Eff.Reader.Strict.Reader x : e)) instance Control.Monad.Catch.MonadThrow m => Control.Monad.Catch.MonadThrow (Control.Eff.Internal.Eff '[Control.Eff.Internal.Lift m]) instance Control.Monad.Catch.MonadCatch m => Control.Monad.Catch.MonadCatch (Control.Eff.Internal.Eff '[Control.Eff.Internal.Lift m]) instance Control.Monad.Catch.MonadMask m => Control.Monad.Catch.MonadMask (Control.Eff.Internal.Eff '[Control.Eff.Internal.Lift m]) instance Control.Monad.Catch.MonadThrow (Control.Eff.Internal.Eff e) => Control.Monad.Catch.MonadThrow (Control.Eff.Internal.Eff (Control.Eff.Exception.Exc x : e)) instance Control.Monad.Catch.MonadCatch (Control.Eff.Internal.Eff e) => Control.Monad.Catch.MonadCatch (Control.Eff.Internal.Eff (Control.Eff.Exception.Exc x : e)) instance Control.Monad.Catch.MonadMask (Control.Eff.Internal.Eff e) => Control.Monad.Catch.MonadMask (Control.Eff.Internal.Eff (Control.Eff.Exception.Exc x : e)) -- | An RFC 5434 inspired log message and convenience functions for logging -- them. module Control.Eff.Log.Message -- | A message data type inspired by the RFC-5424 Syslog Protocol data LogMessage MkLogMessage :: !Facility -> !Severity -> Maybe UTCTime -> Maybe Text -> Maybe Text -> Maybe Text -> Maybe Text -> [StructuredDataElement] -> Maybe ThreadId -> Maybe SrcLoc -> Text -> LogMessage [_lmFacility] :: LogMessage -> !Facility [_lmSeverity] :: LogMessage -> !Severity [_lmTimestamp] :: LogMessage -> Maybe UTCTime [_lmHostname] :: LogMessage -> Maybe Text [_lmAppName] :: LogMessage -> Maybe Text [_lmProcessId] :: LogMessage -> Maybe Text [_lmMessageId] :: LogMessage -> Maybe Text [_lmStructuredData] :: LogMessage -> [StructuredDataElement] [_lmThreadId] :: LogMessage -> Maybe ThreadId [_lmSrcLoc] :: LogMessage -> Maybe SrcLoc [_lmMessage] :: LogMessage -> Text -- | A lens for the Facility of a LogMessage lmFacility :: Functor f => (Facility -> f Facility) -> LogMessage -> f LogMessage -- | A lens for the Severity of a LogMessage lmSeverity :: Functor f => (Severity -> f Severity) -> LogMessage -> f LogMessage -- | A lens for the UTC time of a LogMessage The function -- setLogMessageTimestamp can be used to set the field. lmTimestamp :: Functor f => (Maybe UTCTime -> f (Maybe UTCTime)) -> LogMessage -> f LogMessage -- | A lens for the hostname of a LogMessage The function -- setLogMessageHostname can be used to set the field. lmHostname :: Functor f => (Maybe Text -> f (Maybe Text)) -> LogMessage -> f LogMessage -- | A lens for the RFC 5424 application name of a LogMessage -- -- One useful pattern for using this field, is to implement log filters -- that allow info and debug message from the application itself while -- only allowing warning and error messages from third party libraries: -- --
-- debugLogsForAppName myAppName lm = -- view lmAppName lm == Just myAppName || lmSeverityIsAtLeast warningSeverity lm ---- -- This concept is also implemented in discriminateByAppName. lmAppName :: Functor f => (Maybe Text -> f (Maybe Text)) -> LogMessage -> f LogMessage -- | A lens for a user defined of process id of a LogMessage lmProcessId :: Functor f => (Maybe Text -> f (Maybe Text)) -> LogMessage -> f LogMessage -- | A lens for a user defined message id of a LogMessage lmMessageId :: Functor f => (Maybe Text -> f (Maybe Text)) -> LogMessage -> f LogMessage -- | A lens for the StructuredDataElement of a LogMessage lmStructuredData :: Functor f => ([StructuredDataElement] -> f [StructuredDataElement]) -> LogMessage -> f LogMessage -- | A lens for the SrcLoc of a LogMessage lmSrcLoc :: Functor f => (Maybe SrcLoc -> f (Maybe SrcLoc)) -> LogMessage -> f LogMessage -- | A lens for the ThreadId of a LogMessage The function -- setLogMessageThreadId can be used to set the field. lmThreadId :: Functor f => (Maybe ThreadId -> f (Maybe ThreadId)) -> LogMessage -> f LogMessage -- | A lens for the user defined textual message of a LogMessage lmMessage :: Functor f => (Text -> f Text) -> LogMessage -> f LogMessage -- | Put the source location of the given callstack in lmSrcLoc setCallStack :: CallStack -> LogMessage -> LogMessage -- | Prefix the lmMessage. prefixLogMessagesWith :: Text -> LogMessage -> LogMessage -- | An IO action that sets the current UTC time in lmTimestamp. setLogMessageTimestamp :: LogMessage -> IO LogMessage -- | An IO action appends the the ThreadId of the calling process -- (see myThreadId) to lmMessage. setLogMessageThreadId :: LogMessage -> IO LogMessage -- | An IO action that sets the current hosts fully qualified hostname in -- lmHostname. setLogMessageHostname :: LogMessage -> IO LogMessage -- | Construct a LogMessage with errorSeverity errorMessage :: HasCallStack => Text -> LogMessage -- | Construct a LogMessage with informationalSeverity infoMessage :: HasCallStack => Text -> LogMessage -- | Construct a LogMessage with debugSeverity debugMessage :: HasCallStack => Text -> LogMessage -- | Things that can become a LogMessage class ToLogMessage a -- | Convert the value to a LogMessage toLogMessage :: ToLogMessage a => a -> LogMessage -- | Construct a LogMessage with errorSeverity errorMessageIO :: (HasCallStack, MonadIO m) => Text -> m LogMessage -- | Construct a LogMessage with informationalSeverity infoMessageIO :: (HasCallStack, MonadIO m) => Text -> m LogMessage -- | Construct a LogMessage with debugSeverity debugMessageIO :: (HasCallStack, MonadIO m) => Text -> m LogMessage -- | The filter predicate for message that shall be logged. -- -- See Control.Eff.Log#LogPredicate type LogPredicate = LogMessage -> Bool -- | All messages. -- -- See Control.Eff.Log.Message#PredefinedPredicates for more -- predicates. allLogMessages :: LogPredicate -- | No messages. -- -- See Control.Eff.Log.Message#PredefinedPredicates for more -- predicates. noLogMessages :: LogPredicate -- | Match LogMessages that have exactly the given severity. See -- lmSeverityIsAtLeast. -- -- See Control.Eff.Log.Message#PredefinedPredicates for more -- predicates. lmSeverityIs :: Severity -> LogPredicate -- | Match LogMessages that have the given severity or worse. -- See lmSeverityIs. -- -- See Control.Eff.Log.Message#PredefinedPredicates for more -- predicates. lmSeverityIsAtLeast :: Severity -> LogPredicate -- | Match LogMessages whose lmMessage starts with the given -- string. -- -- See Control.Eff.Log.Message#PredefinedPredicates for more -- predicates. lmMessageStartsWith :: Text -> LogPredicate -- | Apply a LogPredicate based on the lmAppName and delegate -- to one of two LogPredicates. -- -- One useful application for this is to allow info and debug message -- from one application, e.g. the current application itself, while at -- the same time allowing only warning and error messages from third -- party libraries. -- -- See Control.Eff.Log.Message#PredefinedPredicates for more -- predicates. discriminateByAppName :: Text -> LogPredicate -> LogPredicate -> LogPredicate -- | RFC-5424 defines how structured data can be included in a log message. data StructuredDataElement SdElement :: !Text -> ![SdParameter] -> StructuredDataElement [_sdElementId] :: StructuredDataElement -> !Text [_sdElementParameters] :: StructuredDataElement -> ![SdParameter] -- | Component of an RFC-5424 StructuredDataElement data SdParameter MkSdParameter :: !Text -> !Text -> SdParameter -- | A lens for the key or ID of a group of RFC 5424 key-value pairs. sdElementId :: Functor f => (Text -> f Text) -> StructuredDataElement -> f StructuredDataElement -- | A lens for SdParameters sdElementParameters :: Functor f => ([SdParameter] -> f [SdParameter]) -> StructuredDataElement -> f StructuredDataElement -- | An rfc 5424 severity data Severity -- | Smart constructor for the RFC-5424 emergency LogMessage -- Severity. This corresponds to the severity value 0. See -- lmSeverity. emergencySeverity :: Severity -- | Smart constructor for the RFC-5424 alert LogMessage -- Severity. This corresponds to the severity value 1. See -- lmSeverity. alertSeverity :: Severity -- | Smart constructor for the RFC-5424 critical LogMessage -- Severity. This corresponds to the severity value 2. See -- lmSeverity. criticalSeverity :: Severity -- | Smart constructor for the RFC-5424 error LogMessage -- Severity. This corresponds to the severity value 3. See -- lmSeverity. errorSeverity :: Severity -- | Smart constructor for the RFC-5424 warning LogMessage -- Severity. This corresponds to the severity value 4. See -- lmSeverity. warningSeverity :: Severity -- | Smart constructor for the RFC-5424 notice LogMessage -- Severity. This corresponds to the severity value 5. See -- lmSeverity. noticeSeverity :: Severity -- | Smart constructor for the RFC-5424 informational -- LogMessage Severity. This corresponds to the severity -- value 6. See lmSeverity. informationalSeverity :: Severity -- | Smart constructor for the RFC-5424 debug LogMessage -- Severity. This corresponds to the severity value 7. See -- lmSeverity. debugSeverity :: Severity -- | An rfc 5424 facility newtype Facility Facility :: Int -> Facility [fromFacility] :: Facility -> Int -- | Smart constructor for the RFC-5424 LogMessage facility -- kernelMessages. See lmFacility. kernelMessages :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- userLevelMessages. See lmFacility. userLevelMessages :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- mailSystem. See lmFacility. mailSystem :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- systemDaemons. See lmFacility. systemDaemons :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- securityAuthorizationMessages4. See lmFacility. securityAuthorizationMessages4 :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- linePrinterSubsystem. See lmFacility. linePrinterSubsystem :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- networkNewsSubsystem. See lmFacility. networkNewsSubsystem :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- uucpSubsystem. See lmFacility. uucpSubsystem :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- clockDaemon. See lmFacility. clockDaemon :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- securityAuthorizationMessages10. See lmFacility. securityAuthorizationMessages10 :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- ftpDaemon. See lmFacility. ftpDaemon :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- ntpSubsystem. See lmFacility. ntpSubsystem :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- logAuditFacility. See lmFacility. logAuditFacility :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- logAlertFacility. See lmFacility. logAlertFacility :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- clockDaemon2. See lmFacility. clockDaemon2 :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- local0. See lmFacility. local0 :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- local1. See lmFacility. local1 :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- local2. See lmFacility. local2 :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- local3. See lmFacility. local3 :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- local4. See lmFacility. local4 :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- local5. See lmFacility. local5 :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- local6. See lmFacility. local6 :: Facility -- | Smart constructor for the RFC-5424 LogMessage facility -- local7. See lmFacility. local7 :: Facility instance Control.Eff.Log.Message.ToLogMessage Control.Eff.Log.Message.LogMessage instance Control.Eff.Log.Message.ToLogMessage Data.Text.Internal.Text instance Data.String.IsString Control.Eff.Log.Message.LogMessage instance GHC.Generics.Generic Control.Eff.Log.Message.LogMessage instance GHC.Classes.Eq Control.Eff.Log.Message.LogMessage instance Control.DeepSeq.NFData Control.Eff.Log.Message.Facility instance GHC.Generics.Generic Control.Eff.Log.Message.Facility instance GHC.Show.Show Control.Eff.Log.Message.Facility instance GHC.Classes.Ord Control.Eff.Log.Message.Facility instance GHC.Classes.Eq Control.Eff.Log.Message.Facility instance Control.DeepSeq.NFData Control.Eff.Log.Message.Severity instance GHC.Generics.Generic Control.Eff.Log.Message.Severity instance GHC.Classes.Ord Control.Eff.Log.Message.Severity instance GHC.Classes.Eq Control.Eff.Log.Message.Severity instance GHC.Show.Show Control.Eff.Log.Message.StructuredDataElement instance GHC.Generics.Generic Control.Eff.Log.Message.StructuredDataElement instance GHC.Classes.Ord Control.Eff.Log.Message.StructuredDataElement instance GHC.Classes.Eq Control.Eff.Log.Message.StructuredDataElement instance GHC.Show.Show Control.Eff.Log.Message.SdParameter instance GHC.Generics.Generic Control.Eff.Log.Message.SdParameter instance GHC.Classes.Ord Control.Eff.Log.Message.SdParameter instance GHC.Classes.Eq Control.Eff.Log.Message.SdParameter instance Data.Default.Class.Default Control.Eff.Log.Message.LogMessage instance GHC.Show.Show Control.Eff.Log.Message.LogMessage instance Control.DeepSeq.NFData Control.Eff.Log.Message.LogMessage instance Data.Default.Class.Default Control.Eff.Log.Message.Facility instance GHC.Show.Show Control.Eff.Log.Message.Severity instance Data.Default.Class.Default Control.Eff.Log.Message.Severity instance Control.DeepSeq.NFData Control.Eff.Log.Message.StructuredDataElement instance Control.DeepSeq.NFData Control.Eff.Log.Message.SdParameter -- | Rendering functions for LogMessages. module Control.Eff.Log.MessageRenderer -- | LogMessage rendering function type LogMessageRenderer a = LogMessage -> a -- | Render the LogMessage to contain the severity, message, -- message-id, pid. -- -- Omit hostname, PID and timestamp. -- -- Render the header using renderSyslogSeverity -- -- Useful for logging to devlog renderLogMessageSyslog :: LogMessageRenderer Text -- | Render a LogMessage human readable, for console logging renderLogMessageConsoleLog :: LogMessageRenderer Text -- | Render a LogMessage according to the rules in the RFC-3164. renderRFC3164 :: LogMessageRenderer Text -- | Render a LogMessage according to the rules in the RFC-3164 but -- use RFC5424 time stamps. renderRFC3164WithRFC5424Timestamps :: LogMessageRenderer Text -- | Render a LogMessage according to the rules in the RFC-3164 but -- use the custom LogMessageTimeRenderer. renderRFC3164WithTimestamp :: LogMessageTimeRenderer -> LogMessageRenderer Text -- | Render a LogMessage according to the rules in the RFC-5424. -- -- Equivalent to renderRFC5424Header <> const " " -- <> renderLogMessageBody. renderRFC5424 :: LogMessageRenderer Text -- | Render the header and strucuted data of a LogMessage according -- to the rules in the RFC-5424, but do not render the lmMessage. renderRFC5424Header :: LogMessageRenderer Text -- | Render a LogMessage according to the rules in the RFC-5424, -- like renderRFC5424 but suppress the source location -- information. -- -- Equivalent to renderRFC5424Header <> const " " -- <> renderLogMessageBodyNoLocation. renderRFC5424NoLocation :: LogMessageRenderer Text -- | Render the severity and facility as described in RFC-3164 -- -- Render e.g. as <192>. -- -- Useful as header for syslog compatible log output. renderSyslogSeverityAndFacility :: LogMessageRenderer Text -- | Render the source location as: at filepath:linenumber. renderLogMessageSrcLoc :: LogMessageRenderer (Maybe Text) -- | Render a field of a LogMessage using the corresponsing lens. renderMaybeLogMessageLens :: Text -> Getter LogMessage (Maybe Text) -> LogMessageRenderer Text -- | Print the thread id, the message and the source file location, -- seperated by simple white space. renderLogMessageBodyNoLocation :: LogMessageRenderer Text -- | Print the thread id, the message and the source file location, -- seperated by simple white space. renderLogMessageBody :: LogMessageRenderer Text -- | Print the body of a LogMessage with fix size fields (60) -- for the message itself and 30 characters for the location renderLogMessageBodyFixWidth :: LogMessageRenderer Text -- | A rendering function for the lmTimestamp field. data LogMessageTimeRenderer -- | Make a LogMessageTimeRenderer using formatTime in the -- defaultLocale. mkLogMessageTimeRenderer :: String -> LogMessageTimeRenderer -- | Don't render the time stamp suppressTimestamp :: LogMessageTimeRenderer -- | Render the time stamp using "%h %d %H:%M:%S" rfc3164Timestamp :: LogMessageTimeRenderer -- | Render the time stamp to iso8601DateFormat (Just -- "%H:%M:%S%6QZ") rfc5424Timestamp :: LogMessageTimeRenderer -- | Render the time stamp like rfc5424Timestamp does, but omit the -- terminal Z character. rfc5424NoZTimestamp :: LogMessageTimeRenderer -- | The LogWriter type encapsulates an effectful function to write -- LogMessages. -- -- Used in conjunction with the HandleLogWriter class, it can be -- used to write messages from within an effectful computation. module Control.Eff.Log.Writer -- | A function that takes a log message and returns an effect that -- logs the message. newtype LogWriter writerM MkLogWriter :: (LogMessage -> writerM ()) -> LogWriter writerM [runLogWriter] :: LogWriter writerM -> LogMessage -> writerM () -- | A Reader specialized for LogWriters -- -- The existing Reader couldn't be used together with -- SetMember, so this lazy reader was written, specialized to -- reading LogWriter. data LogWriterReader h v -- | Modify the current LogWriter. localLogWriterReader :: forall h e a. SetMember LogWriterReader (LogWriterReader h) e => (LogWriter h -> LogWriter h) -> Eff e a -> Eff e a -- | Get the current LogWriter. askLogWriter :: SetMember LogWriterReader (LogWriterReader h) e => Eff e (LogWriter h) -- | Provide the LogWriter -- -- Exposed for custom extensions, if in doubt use withLogging. runLogWriterReader :: LogWriter h -> Eff (LogWriterReader h : e) a -> Eff e a -- | The instances of this class are the monads that define (side-) -- effect(s) of writting logs. class HandleLogWriter (writerEff :: Type -> Type) e -- | Run the side effect of a LogWriter in a compatible Eff. handleLogWriterEffect :: HandleLogWriter writerEff e => writerEff () -> Eff e () -- | Write a message using the LogWriter found in the environment. -- -- The semantics of this function are a combination of -- runLogWriter and handleLogWriterEffect, with the -- LogWriter read from a LogWriterReader. liftWriteLogMessage :: (HandleLogWriter writerEff e, SetMember LogWriterReader (LogWriterReader writerEff) e) => LogMessage -> Eff e () -- | This LogWriter will discard all messages. -- -- NOTE: This is just an alias for def noOpLogWriter :: Applicative m => LogWriter m -- | A phantom type for the HandleLogWriter class for pure -- LogWriters newtype PureLogWriter a MkPureLogWriter :: Identity a -> PureLogWriter a [runPureLogWriter] :: PureLogWriter a -> Identity a -- | A LogWriter that applies a predicate to the LogMessage -- and delegates to to the given writer of the predicate is satisfied. filteringLogWriter :: Monad e => LogPredicate -> LogWriter e -> LogWriter e -- | A LogWriter that applies a function to the LogMessage -- and delegates the result to to the given writer. mappingLogWriter :: (LogMessage -> LogMessage) -> LogWriter e -> LogWriter e -- | Like mappingLogWriter allow the function that changes the -- LogMessage to have effects. mappingLogWriterM :: Monad e => (LogMessage -> e LogMessage) -> LogWriter e -> LogWriter e instance GHC.Base.Monad Control.Eff.Log.Writer.PureLogWriter instance GHC.Base.Functor Control.Eff.Log.Writer.PureLogWriter instance GHC.Base.Applicative Control.Eff.Log.Writer.PureLogWriter instance Control.Eff.Log.Writer.HandleLogWriter Control.Eff.Log.Writer.PureLogWriter e instance Control.Eff.Internal.Lifted GHC.Types.IO e => Control.Eff.Log.Writer.HandleLogWriter GHC.Types.IO e instance Control.Eff.Internal.Handle (Control.Eff.Log.Writer.LogWriterReader h) e a (Control.Eff.Log.Writer.LogWriter h -> k) instance (Control.Monad.Base.MonadBase m m, Control.Eff.Internal.LiftedBase m r) => Control.Monad.Trans.Control.MonadBaseControl m (Control.Eff.Internal.Eff (Control.Eff.Log.Writer.LogWriterReader h : r)) instance (Control.Eff.Internal.LiftedBase m e, Control.Monad.Catch.MonadThrow (Control.Eff.Internal.Eff e)) => Control.Monad.Catch.MonadThrow (Control.Eff.Internal.Eff (Control.Eff.Log.Writer.LogWriterReader h : e)) instance (GHC.Base.Applicative m, Control.Eff.Internal.LiftedBase m e, Control.Monad.Catch.MonadCatch (Control.Eff.Internal.Eff e)) => Control.Monad.Catch.MonadCatch (Control.Eff.Internal.Eff (Control.Eff.Log.Writer.LogWriterReader h : e)) instance (GHC.Base.Applicative m, Control.Eff.Internal.LiftedBase m e, Control.Monad.Catch.MonadMask (Control.Eff.Internal.Eff e)) => Control.Monad.Catch.MonadMask (Control.Eff.Internal.Eff (Control.Eff.Log.Writer.LogWriterReader h : e)) instance GHC.Base.Applicative w => Data.Default.Class.Default (Control.Eff.Log.Writer.LogWriter w) -- | A memory efficient, streaming, logging effect with support for -- efficiently not logging when no logs are required. -- -- Good support for logging to a file or to the network, as well as -- asynchronous logging in another thread. module Control.Eff.Log.Handler -- | Log a message. -- -- All logging goes through this function. -- -- This function is the only place where the LogPredicate is -- applied. -- -- Also, LogMessages are evaluated using deepseq, -- after they pass the LogPredicate. logMsg :: forall e. (HasCallStack, Member Logs e) => LogMessage -> Eff e () -- | Log a Text as LogMessage with a given Severity. logWithSeverity :: forall e. (HasCallStack, Member Logs e) => Severity -> Text -> Eff e () -- | Log a Text as LogMessage with a given Severity. logWithSeverity' :: forall e. (HasCallStack, Member Logs e) => Severity -> String -> Eff e () -- | Log a String as emergencySeverity. logEmergency :: forall e. (HasCallStack, Member Logs e) => Text -> Eff e () -- | Log a String as emergencySeverity. logEmergency' :: forall e. (HasCallStack, Member Logs e) => String -> Eff e () -- | Log a message with alertSeverity. logAlert :: forall e. (HasCallStack, Member Logs e) => Text -> Eff e () -- | Log a message with alertSeverity. logAlert' :: forall e. (HasCallStack, Member Logs e) => String -> Eff e () -- | Log a criticalSeverity message. logCritical :: forall e. (HasCallStack, Member Logs e) => Text -> Eff e () -- | Log a criticalSeverity message. logCritical' :: forall e. (HasCallStack, Member Logs e) => String -> Eff e () -- | Log a errorSeverity message. logError :: forall e. (HasCallStack, Member Logs e) => Text -> Eff e () -- | Log a errorSeverity message. logError' :: forall e. (HasCallStack, Member Logs e) => String -> Eff e () -- | Log a warningSeverity message. logWarning :: forall e. (HasCallStack, Member Logs e) => Text -> Eff e () -- | Log a warningSeverity message. logWarning' :: forall e. (HasCallStack, Member Logs e) => String -> Eff e () -- | Log a noticeSeverity message. logNotice :: forall e. (HasCallStack, Member Logs e) => Text -> Eff e () -- | Log a noticeSeverity message. logNotice' :: forall e. (HasCallStack, Member Logs e) => String -> Eff e () -- | Log a informationalSeverity message. logInfo :: forall e. (HasCallStack, Member Logs e) => Text -> Eff e () -- | Log a informationalSeverity message. logInfo' :: forall e. (HasCallStack, Member Logs e) => String -> Eff e () -- | Log a debugSeverity message. logDebug :: forall e. (HasCallStack, Member Logs e) => Text -> Eff e () -- | Log a debugSeverity message. logDebug' :: forall e. (HasCallStack, Member Logs e) => String -> Eff e () -- | Include LogMessages that match a LogPredicate. -- -- excludeLogMessages p allows log message to be logged if p -- m -- -- Although it is enough if the previous predicate holds. See -- excludeLogMessages and modifyLogPredicate. -- -- See Control.Eff.Log#LogPredicate includeLogMessages :: forall e a. Member Logs e => LogPredicate -> Eff e a -> Eff e a -- | Exclude LogMessages that match a LogPredicate. -- -- excludeLogMessages p discards logs if p m -- -- Also the previous predicate must also hold for a message to be logged. -- See excludeLogMessages and modifyLogPredicate. -- -- See Control.Eff.Log#LogPredicate excludeLogMessages :: forall e a. Member Logs e => LogPredicate -> Eff e a -> Eff e a -- | Keep only those messages, for which a predicate holds. -- -- E.g. to keep only messages which begin with OMG: -- --
-- exampleLogPredicate :: IO Int -- exampleLogPredicate = -- runLift -- $ withLogging consoleLogWriter -- $ do logMsg "test" -- setLogPredicate (\ msg -> case view lmMessage msg of -- 'O':'M':'G':_ -> True -- _ -> False) -- (do logMsg "this message will not be logged" -- logMsg "OMG logged" -- return 42) ---- -- In order to also delegate to the previous predicate, use -- modifyLogPredicate -- -- See Control.Eff.Log#LogPredicate setLogPredicate :: forall r b. (Member Logs r, HasCallStack) => LogPredicate -> Eff r b -> Eff r b -- | Change the LogPredicate. -- -- Other than setLogPredicate this function allows to include the -- previous predicate, too. -- -- For to discard all messages currently no satisfying the predicate and -- also all messages that are to long: -- --
-- modifyLogPredicate (previousPredicate msg -> previousPredicate msg && length (lmMessage msg) < 29 ) -- (do logMsg "this message will not be logged" -- logMsg "this message might be logged") ---- -- See Control.Eff.Log#LogPredicate modifyLogPredicate :: forall e b. (Member Logs e, HasCallStack) => (LogPredicate -> LogPredicate) -> Eff e b -> Eff e b -- | Get the current Logs filter/transformer function. -- -- See Control.Eff.Log#LogPredicate askLogPredicate :: forall e. Member Logs e => Eff e LogPredicate -- | Replace the current LogWriter. To add an additional log message -- consumer use addLogWriter setLogWriter :: forall h e a. LogsTo h e => LogWriter h -> Eff e a -> Eff e a -- | Combine the effects of a given LogWriter and the existing one. -- --
-- import Data.Text as T
-- import Data.Text.IO as T
--
-- exampleAddLogWriter :: IO ()
-- exampleAddLogWriter = go >>= T.putStrLn
-- where go = fmap (unlines . map renderLogMessageConsoleLog . snd)
-- $ runLift
-- $ runCaptureLogWriter
-- $ withLogging captureLogWriter
-- $ addLogWriter (mappingLogWriter (lmMessage %~ ("CAPTURED "++)) captureLogWriter)
-- $ addLogWriter (filteringLogWriter severeMessages (mappingLogWriter (lmMessage %~ ("TRACED "++)) debugTraceLogWriter))
-- $ do
-- logEmergency "test emergencySeverity 1"
-- logCritical "test criticalSeverity 2"
-- logAlert "test alertSeverity 3"
-- logError "test errorSeverity 4"
-- logWarning "test warningSeverity 5"
-- logInfo "test informationalSeverity 6"
-- logDebug "test debugSeverity 7"
-- severeMessages = view (lmSeverity . to (<= errorSeverity))
--
addLogWriter :: forall h e a. (HasCallStack, LogsTo h e, Monad h) => LogWriter h -> Eff e a -> Eff e a
-- | Change the current LogWriter.
modifyLogWriter :: forall h e a. LogsTo h e => (LogWriter h -> LogWriter h) -> Eff e a -> Eff e a
-- | Modify the the LogMessages written in the given sub-expression.
--
-- Note: This is equivalent to modifyLogWriter .
-- mappingLogWriter
censorLogs :: LogsTo h e => (LogMessage -> LogMessage) -> Eff e a -> Eff e a
-- | Modify the the LogMessages written in the given sub-expression,
-- as in censorLogs but with a effectful function.
--
-- Note: This is equivalent to modifyLogWriter .
-- mappingLogWriterM
censorLogsM :: (LogsTo h e, Monad h) => (LogMessage -> h LogMessage) -> Eff e a -> Eff e a
-- | This effect sends LogMessages and is a reader for a
-- LogPredicate.
--
-- Logs are sent via logMsg; for more information about log
-- predicates, see Control.Eff.Log#LogPredicate
--
-- This effect is handled via withLogging.
data Logs v
-- | A constraint alias for effects that requires a LogWriterReader,
-- as well as that the contained LogWriterReader has a
-- HandleLogWriter instance.
--
-- The requirements of this constraint are provided by:
--
-- -- exampleWithLogging :: IO () -- exampleWithLogging = -- runLift -- $ withLogging consoleLogWriter -- $ logDebug "Oh, hi there" --withLogging :: forall h e a. (Applicative h, LogsTo h (Logs : (LogWriterReader h : e))) => LogWriter h -> Eff (Logs : (LogWriterReader h : e)) a -> Eff e a -- | Handles the Logs and LogWriterReader effects. -- -- By default it uses the noOpLogWriter, but using -- setLogWriter the LogWriter can be replaced. -- -- This is like withLogging applied to noOpLogWriter -- -- Example: -- --
-- exampleWithSomeLogging :: () -- exampleWithSomeLogging = -- run -- $ withSomeLogging @PureLogWriter -- $ logDebug "Oh, hi there" --withSomeLogging :: forall h e a. (Applicative h, LogsTo h (Logs : (LogWriterReader h : e))) => Eff (Logs : (LogWriterReader h : e)) a -> Eff e a -- | Raw handling of the Logs effect. Exposed for custom extensions, -- if in doubt use withLogging. runLogs :: forall h e b. LogsTo h (Logs : e) => LogPredicate -> Eff (Logs : e) b -> Eff e b -- | Consume log messages. -- -- Exposed for custom extensions, if in doubt use withLogging. -- -- Respond to all LogMessages logged from the given action, up to -- any MonadBaseControl liftings. -- -- Note that all logging is done through logMsg and that means -- only messages passing the LogPredicate are received. -- -- The LogMessages are consumed once they are passed to the -- given callback function, previous respondToLogMessage -- invocations further up in the call stack will not get the messages -- anymore. -- -- Use interceptLogMessages if the messages shall be passed any -- previous handler. -- -- NOTE: The effects of this function are lost when using -- MonadBaseControl, MonadMask, MonadCatch and -- MonadThrow. -- -- In contrast the functions based on modifying the LogWriter, -- such as addLogWriter or censorLogs, are save to use in -- combination with the aforementioned liftings. respondToLogMessage :: forall r b. Member Logs r => (LogMessage -> Eff r ()) -> Eff r b -> Eff r b -- | Change the LogMessages using an effectful function. -- -- Exposed for custom extensions, if in doubt use withLogging. -- -- This differs from respondToLogMessage in that the intercepted -- messages will be written either way, albeit in altered form. -- -- NOTE: The effects of this function are lost when using -- MonadBaseControl, MonadMask, MonadCatch and -- MonadThrow. -- -- In contrast the functions based on modifying the LogWriter, -- such as addLogWriter or censorLogs, are save to use in -- combination with the aforementioned liftings. interceptLogMessages :: forall r b. Member Logs r => (LogMessage -> Eff r LogMessage) -> Eff r b -> Eff r b instance (Control.Monad.Base.MonadBase m m, Control.Eff.Internal.LiftedBase m e, Control.Eff.Log.Handler.LogsTo m (Control.Eff.Log.Handler.Logs : e)) => Control.Monad.Trans.Control.MonadBaseControl m (Control.Eff.Internal.Eff (Control.Eff.Log.Handler.Logs : e)) instance (GHC.Base.Applicative m, Control.Eff.Internal.LiftedBase m e, Control.Monad.Catch.MonadCatch (Control.Eff.Internal.Eff e), Control.Eff.Log.Handler.LogsTo m (Control.Eff.Log.Handler.Logs : e)) => Control.Monad.Catch.MonadCatch (Control.Eff.Internal.Eff (Control.Eff.Log.Handler.Logs : e)) instance (GHC.Base.Applicative m, Control.Eff.Internal.LiftedBase m e, Control.Monad.Catch.MonadMask (Control.Eff.Internal.Eff e), Control.Eff.Log.Handler.LogsTo m (Control.Eff.Log.Handler.Logs : e)) => Control.Monad.Catch.MonadMask (Control.Eff.Internal.Eff (Control.Eff.Log.Handler.Logs : e)) instance Control.Eff.Internal.Handle Control.Eff.Log.Handler.Logs e a (Control.Eff.Log.Message.LogPredicate -> k) instance (Control.Eff.Internal.LiftedBase m e, Control.Monad.Catch.MonadThrow (Control.Eff.Internal.Eff e)) => Control.Monad.Catch.MonadThrow (Control.Eff.Internal.Eff (Control.Eff.Log.Handler.Logs : e)) -- | The message passing effect. -- -- This module describes an abstract message passing effect, and a -- process effect, mimicking Erlang's process and message semantics. -- -- Two scheduler implementations for the Process effect are -- provided: -- --
-- logCrash :: Interrupt -> Eff e () -- logCrash (toCrashReason -> Just reason) = logError reason -- logCrash _ = return () ---- -- Though this can be improved to: -- --
-- logCrash = traverse_ logError . toCrashReason --toCrashReason :: Interrupt x -> Maybe Text -- | Partition a SomeExitReason back into either a NoRecovery -- or a Recoverable Interrupt fromSomeExitReason :: SomeExitReason -> Either (Interrupt 'NoRecovery) (Interrupt 'Recoverable) -- | Log the Interrupts logProcessExit :: forall e x. (Member Logs e, HasCallStack) => Interrupt x -> Eff e () instance GHC.Show.Show v => GHC.Show.Show (Control.Eff.Concurrent.Process.ResumeProcess v) instance GHC.Generics.Generic1 Control.Eff.Concurrent.Process.ResumeProcess instance GHC.Generics.Generic (Control.Eff.Concurrent.Process.ResumeProcess v) instance GHC.Classes.Ord Control.Eff.Concurrent.Process.ProcessDown instance GHC.Classes.Eq Control.Eff.Concurrent.Process.ProcessDown instance GHC.Generics.Generic Control.Eff.Concurrent.Process.ProcessDown instance GHC.Generics.Generic Control.Eff.Concurrent.Process.MonitorReference instance GHC.Classes.Ord Control.Eff.Concurrent.Process.MonitorReference instance GHC.Classes.Eq Control.Eff.Concurrent.Process.MonitorReference instance GHC.Read.Read Control.Eff.Concurrent.Process.MonitorReference instance Control.DeepSeq.NFData Control.Eff.Concurrent.Process.ProcessId instance GHC.Real.Real Control.Eff.Concurrent.Process.ProcessId instance GHC.Real.Integral Control.Eff.Concurrent.Process.ProcessId instance GHC.Enum.Enum Control.Eff.Concurrent.Process.ProcessId instance GHC.Num.Num Control.Eff.Concurrent.Process.ProcessId instance GHC.Enum.Bounded Control.Eff.Concurrent.Process.ProcessId instance GHC.Classes.Ord Control.Eff.Concurrent.Process.ProcessId instance GHC.Classes.Eq Control.Eff.Concurrent.Process.ProcessId instance GHC.Generics.Generic Control.Eff.Concurrent.Process.ExitSeverity instance GHC.Classes.Eq Control.Eff.Concurrent.Process.ExitSeverity instance GHC.Classes.Ord Control.Eff.Concurrent.Process.ExitSeverity instance GHC.Generics.Generic Control.Eff.Concurrent.Process.ExitRecovery instance GHC.Classes.Eq Control.Eff.Concurrent.Process.ExitRecovery instance GHC.Classes.Ord Control.Eff.Concurrent.Process.ExitRecovery instance GHC.Generics.Generic Control.Eff.Concurrent.Process.ProcessState instance GHC.Enum.Enum Control.Eff.Concurrent.Process.ProcessState instance GHC.Classes.Eq Control.Eff.Concurrent.Process.ProcessState instance GHC.Classes.Ord Control.Eff.Concurrent.Process.ProcessState instance GHC.Show.Show Control.Eff.Concurrent.Process.ProcessState instance GHC.Read.Read Control.Eff.Concurrent.Process.ProcessState instance GHC.Base.Functor Control.Eff.Concurrent.Process.MessageSelector instance GHC.Base.Semigroup a => GHC.Base.Monoid (Control.Eff.Concurrent.Process.MessageSelector a) instance GHC.Base.Semigroup a => GHC.Base.Semigroup (Control.Eff.Concurrent.Process.MessageSelector a) instance GHC.Base.Monoid Control.Eff.Concurrent.Process.ProcessDetails instance GHC.Base.Semigroup Control.Eff.Concurrent.Process.ProcessDetails instance Data.String.IsString Control.Eff.Concurrent.Process.ProcessDetails instance GHC.Generics.Generic Control.Eff.Concurrent.Process.ProcessDetails instance Control.DeepSeq.NFData Control.Eff.Concurrent.Process.ProcessDetails instance GHC.Classes.Ord Control.Eff.Concurrent.Process.ProcessDetails instance GHC.Classes.Eq Control.Eff.Concurrent.Process.ProcessDetails instance GHC.Base.Monoid Control.Eff.Concurrent.Process.ProcessTitle instance GHC.Base.Semigroup Control.Eff.Concurrent.Process.ProcessTitle instance Data.String.IsString Control.Eff.Concurrent.Process.ProcessTitle instance GHC.Generics.Generic Control.Eff.Concurrent.Process.ProcessTitle instance Control.DeepSeq.NFData Control.Eff.Concurrent.Process.ProcessTitle instance GHC.Classes.Ord Control.Eff.Concurrent.Process.ProcessTitle instance GHC.Classes.Eq Control.Eff.Concurrent.Process.ProcessTitle instance GHC.Show.Show (Control.Eff.Concurrent.Process.Process r b) instance Control.DeepSeq.NFData a => Control.DeepSeq.NFData (Control.Eff.Concurrent.Process.ResumeProcess a) instance Control.DeepSeq.NFData1 Control.Eff.Concurrent.Process.ResumeProcess instance Control.DeepSeq.NFData Control.Eff.Concurrent.Process.ProcessDown instance GHC.Show.Show Control.Eff.Concurrent.Process.ProcessDown instance GHC.Classes.Ord Control.Eff.Concurrent.Process.SomeExitReason instance GHC.Classes.Eq Control.Eff.Concurrent.Process.SomeExitReason instance GHC.Show.Show Control.Eff.Concurrent.Process.SomeExitReason instance Control.DeepSeq.NFData Control.Eff.Concurrent.Process.SomeExitReason instance GHC.Show.Show (Control.Eff.Concurrent.Process.Interrupt x) instance GHC.Exception.Type.Exception (Control.Eff.Concurrent.Process.Interrupt 'Control.Eff.Concurrent.Process.Recoverable) instance GHC.Exception.Type.Exception (Control.Eff.Concurrent.Process.Interrupt 'Control.Eff.Concurrent.Process.NoRecovery) instance Control.DeepSeq.NFData (Control.Eff.Concurrent.Process.Interrupt x) instance GHC.Classes.Ord (Control.Eff.Concurrent.Process.Interrupt x) instance GHC.Classes.Eq (Control.Eff.Concurrent.Process.Interrupt x) instance Control.DeepSeq.NFData Control.Eff.Concurrent.Process.MonitorReference instance GHC.Show.Show Control.Eff.Concurrent.Process.MonitorReference instance GHC.Read.Read Control.Eff.Concurrent.Process.ProcessId instance GHC.Show.Show Control.Eff.Concurrent.Process.ProcessId instance GHC.Show.Show Control.Eff.Concurrent.Process.ExitSeverity instance Control.DeepSeq.NFData Control.Eff.Concurrent.Process.ExitSeverity instance Control.DeepSeq.NFData Control.Eff.Concurrent.Process.ExitRecovery instance GHC.Show.Show Control.Eff.Concurrent.Process.ExitRecovery instance Control.DeepSeq.NFData Control.Eff.Concurrent.Process.ProcessState instance Data.Default.Class.Default Control.Eff.Concurrent.Process.ProcessState instance GHC.Base.Applicative Control.Eff.Concurrent.Process.MessageSelector instance GHC.Base.Alternative Control.Eff.Concurrent.Process.MessageSelector instance Data.Functor.Contravariant.Contravariant Control.Eff.Concurrent.Process.Serializer instance Control.DeepSeq.NFData Control.Eff.Concurrent.Process.StrictDynamic instance GHC.Show.Show Control.Eff.Concurrent.Process.StrictDynamic instance GHC.Show.Show Control.Eff.Concurrent.Process.ProcessDetails instance GHC.Show.Show Control.Eff.Concurrent.Process.ProcessTitle -- | This module contains a mechanism to specify what kind of messages (aka -- requests) a Endpoint (Process) can handle, and if -- the caller blocks and waits for an answer, which the server process -- provides. -- -- The type magic in the Pdu type family allows to define a -- related set of requests along with the corresponding responses. -- -- Request handling can be either blocking, if a response is required, or -- non-blocking. -- -- A process can serve a specific Pdu instance by using the -- functions provided by the Control.Eff.Concurrent.Pdu.Server -- module. -- -- To enable a process to use such a service, the functions -- provided by the Control.Eff.Concurrent.Pdu.Client should be -- used. module Control.Eff.Concurrent.Protocol -- | This data family defines the **protocol data units**(PDU) of a -- protocol. -- -- A Protocol in the sense of a communication interface description -- between processes. -- -- The first parameter is usually a user defined type that identifies the -- protocol that uses the Pdus are. It maybe a phantom -- type. -- -- The second parameter specifies if a specific constructor of an -- (GADT-like) Pdu instance is Synchronous, i.e. returns -- a result and blocks the caller or if it is Asynchronous -- -- Example: -- --
-- data BookShop deriving Typeable
--
-- data instance Pdu BookShop r where
-- RentBook :: BookId -> Pdu BookShop ('Synchronous (Either RentalError RentalId))
-- BringBack :: RentalId -> Pdu BookShop 'Asynchronous
--
-- type BookId = Int
-- type RentalId = Int
-- type RentalError = String
--
data family Pdu (protocol :: Type) (reply :: Synchronicity)
-- | The (promoted) constructors of this type specify (at the type level)
-- the reply behavior of a specific constructor of an Pdu
-- instance.
data Synchronicity
-- | Specify that handling a request is a blocking operation with a
-- specific return type, e.g. ('Synchronous (Either RentalError
-- RentalId))
Synchronous :: Type -> Synchronicity
-- | Non-blocking, asynchronous, request handling
Asynchronous :: Synchronicity
-- | This type function takes an Pdu and analysis the reply type,
-- i.e. the Synchronicity and evaluates to either t for
-- an Pdu x (Synchronous t) or to '()' for an Pdu x
-- Asynchronous.
type family ProtocolReply (s :: Synchronicity)
-- | A set of constraints for types that can evaluated via NFData,
-- compared via Ord and presented dynamically via Typeable,
-- and represented both as values via Show.
type Tangible i = (NFData i, Typeable i, Show i)
-- | A Constraint that bundles the requirements for the Pdu
-- values of a protocol.
--
-- This ensures that Pdus can be strictly and deeply evaluated and
-- shown such that for example logging is possible.
type TangiblePdu p r = (Typeable p, Typeable r, Tangible (Pdu p r))
-- | This is a tag-type that wraps around a ProcessId and holds an
-- Pdu index type.
newtype Endpoint protocol
Endpoint :: ProcessId -> Endpoint protocol
[_fromEndpoint] :: Endpoint protocol -> ProcessId
fromEndpoint :: forall protocol_aRHy protocol_aRV4. Iso (Endpoint protocol_aRHy) (Endpoint protocol_aRV4) ProcessId ProcessId
-- | Tag a ProcessId with an Pdu type index to mark it a
-- Endpoint process handling that API
proxyAsEndpoint :: proxy protocol -> ProcessId -> Endpoint protocol
-- | Tag a ProcessId with an Pdu type index to mark it a
-- Endpoint process handling that API
asEndpoint :: forall protocol. ProcessId -> Endpoint protocol
-- | A class for Pdu instances that embed other Pdu. A
-- Prism for the embedded Pdu is the center of this class
--
-- Laws: embeddedPdu = prism' embedPdu fromPdu
class EmbedProtocol protocol embeddedProtocol
-- | A Prism for the embedded Pdus.
embeddedPdu :: EmbedProtocol protocol embeddedProtocol => Prism' (Pdu protocol result) (Pdu embeddedProtocol result)
-- | Embed the Pdu value of an embedded protocol into the
-- corresponding Pdu value.
embedPdu :: EmbedProtocol protocol embeddedProtocol => Pdu embeddedProtocol r -> Pdu protocol r
-- | Examine a Pdu value from the outer protocol, and return it, if
-- it embeds a Pdu of embedded protocol, otherwise return
-- Nothing/
fromPdu :: EmbedProtocol protocol embeddedProtocol => Pdu protocol r -> Maybe (Pdu embeddedProtocol r)
-- | This is equivalent to prettyTypeableShowsPrec 0
prettyTypeableShows :: SomeTypeRep -> ShowS
-- | An internal utility to print Typeable without the kinds. This
-- is like showsPrec in that it accepts a precedence
-- parameter, and the result is in parentheses when the precedence is
-- higher than 9.
prettyTypeableShowsPrec :: Int -> SomeTypeRep -> ShowS
instance Control.Eff.Concurrent.Protocol.EmbedProtocol a a
instance Control.Eff.Concurrent.Protocol.EmbedProtocol (a1, a2) a1
instance Control.Eff.Concurrent.Protocol.EmbedProtocol (a1, a2) a2
instance Control.Eff.Concurrent.Protocol.EmbedProtocol (a1, a2, a3) a1
instance Control.Eff.Concurrent.Protocol.EmbedProtocol (a1, a2, a3) a2
instance Control.Eff.Concurrent.Protocol.EmbedProtocol (a1, a2, a3) a3
instance Control.Eff.Concurrent.Protocol.EmbedProtocol (a1, a2, a3, a4) a1
instance Control.Eff.Concurrent.Protocol.EmbedProtocol (a1, a2, a3, a4) a2
instance Control.Eff.Concurrent.Protocol.EmbedProtocol (a1, a2, a3, a4) a3
instance Control.Eff.Concurrent.Protocol.EmbedProtocol (a1, a2, a3, a4) a4
instance Control.Eff.Concurrent.Protocol.EmbedProtocol (a1, a2, a3, a4, a5) a1
instance Control.Eff.Concurrent.Protocol.EmbedProtocol (a1, a2, a3, a4, a5) a2
instance Control.Eff.Concurrent.Protocol.EmbedProtocol (a1, a2, a3, a4, a5) a3
instance Control.Eff.Concurrent.Protocol.EmbedProtocol (a1, a2, a3, a4, a5) a4
instance Control.Eff.Concurrent.Protocol.EmbedProtocol (a1, a2, a3, a4, a5) a5
instance (Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Pdu a1 r), Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Pdu a2 r)) => Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Pdu (a1, a2) r)
instance (GHC.Show.Show (Control.Eff.Concurrent.Protocol.Pdu a1 r), GHC.Show.Show (Control.Eff.Concurrent.Protocol.Pdu a2 r)) => GHC.Show.Show (Control.Eff.Concurrent.Protocol.Pdu (a1, a2) r)
instance (Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Pdu a1 r), Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Pdu a2 r), Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Pdu a3 r)) => Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Pdu (a1, a2, a3) r)
instance (GHC.Show.Show (Control.Eff.Concurrent.Protocol.Pdu a1 r), GHC.Show.Show (Control.Eff.Concurrent.Protocol.Pdu a2 r), GHC.Show.Show (Control.Eff.Concurrent.Protocol.Pdu a3 r)) => GHC.Show.Show (Control.Eff.Concurrent.Protocol.Pdu (a1, a2, a3) r)
instance (Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Pdu a1 r), Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Pdu a2 r), Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Pdu a3 r), Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Pdu a4 r)) => Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Pdu (a1, a2, a3, a4) r)
instance (GHC.Show.Show (Control.Eff.Concurrent.Protocol.Pdu a1 r), GHC.Show.Show (Control.Eff.Concurrent.Protocol.Pdu a2 r), GHC.Show.Show (Control.Eff.Concurrent.Protocol.Pdu a3 r), GHC.Show.Show (Control.Eff.Concurrent.Protocol.Pdu a4 r)) => GHC.Show.Show (Control.Eff.Concurrent.Protocol.Pdu (a1, a2, a3, a4) r)
instance (Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Pdu a1 r), Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Pdu a2 r), Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Pdu a3 r), Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Pdu a4 r), Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Pdu a5 r)) => Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Pdu (a1, a2, a3, a4, a5) r)
instance (GHC.Show.Show (Control.Eff.Concurrent.Protocol.Pdu a1 r), GHC.Show.Show (Control.Eff.Concurrent.Protocol.Pdu a2 r), GHC.Show.Show (Control.Eff.Concurrent.Protocol.Pdu a3 r), GHC.Show.Show (Control.Eff.Concurrent.Protocol.Pdu a4 r), GHC.Show.Show (Control.Eff.Concurrent.Protocol.Pdu a5 r)) => GHC.Show.Show (Control.Eff.Concurrent.Protocol.Pdu (a1, a2, a3, a4, a5) r)
instance forall k (protocol :: k). Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Endpoint protocol)
instance forall k (protocol :: k). GHC.Classes.Ord (Control.Eff.Concurrent.Protocol.Endpoint protocol)
instance forall k (protocol :: k). GHC.Classes.Eq (Control.Eff.Concurrent.Protocol.Endpoint protocol)
instance forall k (protocol :: k). Data.Typeable.Internal.Typeable protocol => GHC.Show.Show (Control.Eff.Concurrent.Protocol.Endpoint protocol)
-- | Proxies and containers for casts and calls.
module Control.Eff.Concurrent.Protocol.Request
-- | A wrapper sum type for calls and casts for the Pdus of a
-- protocol
data Request protocol
[Call] :: forall protocol reply. (Tangible reply, TangiblePdu protocol ( 'Synchronous reply)) => RequestOrigin protocol reply -> Pdu protocol ( 'Synchronous reply) -> Request protocol
[Cast] :: forall protocol. (TangiblePdu protocol 'Asynchronous, NFData (Pdu protocol 'Asynchronous)) => Pdu protocol 'Asynchronous -> Request protocol
-- | Send a Reply to a Call.
--
-- The reply will be deeply evaluated to rnf.
--
-- To send replies for EmbedProtocol instances use
-- embedReplySerializer.
sendReply :: (SetMember Process (Process q) eff, Member Interrupts eff, Tangible reply, Typeable protocol) => Serializer (Reply protocol reply) -> RequestOrigin protocol reply -> reply -> Eff eff ()
-- | Wraps the source ProcessId and a unique identifier for a
-- Call.
data RequestOrigin (proto :: Type) reply
RequestOrigin :: !ProcessId -> !Int -> RequestOrigin reply
[_requestOriginPid] :: RequestOrigin reply -> !ProcessId
[_requestOriginCallRef] :: RequestOrigin reply -> !Int
-- | Turn an embedded RequestOrigin to a RequestOrigin
-- for the bigger request.
--
-- This function is strict in all parameters.
--
-- This is useful of a server delegates the calls and
-- casts for an embedded protocol to functions, that require the
-- Serializer and RequestOrigin in order to call
-- sendReply.
--
-- See also embedReplySerializer.
embedRequestOrigin :: EmbedProtocol outer inner => RequestOrigin inner reply -> RequestOrigin outer reply
-- | The wrapper around replies to Calls.
data Reply protocol reply
[Reply] :: Tangible reply => {_replyTo :: RequestOrigin protocol reply, _replyValue :: reply} -> Reply protocol reply
-- | Turn a Serializer for a Pdu instance that contains
-- embedded Pdu values into a Reply Serializer for
-- the embedded Pdu.
--
-- This is useful of a server delegates the calls and
-- casts for an embedded protocol to functions, that require the
-- Serializer and RequestOrigin in order to call
-- sendReply.
--
-- See also embedRequestOrigin.
embedReplySerializer :: EmbedProtocol outer inner => Serializer (Reply outer reply) -> Serializer (Reply inner reply)
-- | Create a new, unique RequestOrigin value for the current
-- process.
makeRequestOrigin :: (Typeable r, NFData r, SetMember Process (Process q0) e, '[Interrupts] <:: e) => Eff e (RequestOrigin p r)
instance forall proto k (reply :: k). GHC.Classes.Ord (Control.Eff.Concurrent.Protocol.Request.RequestOrigin proto reply)
instance forall proto k (reply :: k). GHC.Classes.Eq (Control.Eff.Concurrent.Protocol.Request.RequestOrigin proto reply)
instance forall proto k (reply :: k). GHC.Generics.Generic (Control.Eff.Concurrent.Protocol.Request.RequestOrigin proto reply)
instance GHC.Show.Show (Control.Eff.Concurrent.Protocol.Request.Request protocol)
instance Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Request.Request protocol)
instance Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Request.Reply p r)
instance GHC.Show.Show r => GHC.Show.Show (Control.Eff.Concurrent.Protocol.Request.Reply p r)
instance forall k p (r :: k). GHC.Show.Show (Control.Eff.Concurrent.Protocol.Request.RequestOrigin p r)
instance forall k p (r :: k). Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Request.RequestOrigin p r)
-- | Functions for timeouts when receiving messages.
--
-- NOTE: If you use a single threaded scheduler, these functions will not
-- work as expected. (This is an open TODO)
module Control.Eff.Concurrent.Process.Timer
-- | A number of micro seconds.
newtype Timeout
TimeoutMicros :: Int -> Timeout
[fromTimeoutMicros] :: Timeout -> Int
-- | The reference to a timer started by startTimer, required to
-- stop a timer via cancelTimer.
data TimerReference
-- | A value to be sent when timer started with startTimer has
-- elapsed.
data TimerElapsed
-- | Send a message to a given process after waiting. The message is
-- created by applying the function parameter to the
-- TimerReference, such that the message can directly refer to the
-- timer.
sendAfter :: forall r q message. (Lifted IO q, HasCallStack, SetMember Process (Process q) r, Member Interrupts r, Typeable message, NFData message) => ProcessId -> Timeout -> (TimerReference -> message) -> Eff r TimerReference
-- | Start a new timer, after the time has elapsed, TimerElapsed is
-- sent to calling process. The message also contains the
-- TimerReference returned by this function. Use
-- cancelTimer to cancel the timer. Use selectTimerElapsed
-- to receive the message using receiveSelectedMessage. To receive
-- messages with guarded with a timeout see receiveAfter.
startTimer :: forall r q. (Lifted IO q, HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => Timeout -> Eff r TimerReference
-- | Cancel a timer started with startTimer.
cancelTimer :: forall r q. (Lifted IO q, HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => TimerReference -> Eff r ()
-- | A MessageSelector matching TimerElapsed messages created
-- by startTimer.
selectTimerElapsed :: TimerReference -> MessageSelector TimerElapsed
-- | Wait for a message of the given type for the given time. When no
-- message arrives in time, return Nothing. This is based on
-- receiveSelectedAfter.
receiveAfter :: forall a r q. (Lifted IO q, HasCallStack, SetMember Process (Process q) r, Member Interrupts r, Typeable a, NFData a, Show a) => Timeout -> Eff r (Maybe a)
-- | Wait for a message of the given type for the given time. When no
-- message arrives in time, return Left TimerElapsed. This
-- is based on selectTimerElapsed and startTimer.
receiveSelectedAfter :: forall a r q. (Lifted IO q, HasCallStack, SetMember Process (Process q) r, Member Interrupts r, Show a) => MessageSelector a -> Timeout -> Eff r (Either TimerElapsed a)
-- | Like receiveWithMonitor combined with
-- receiveSelectedAfter.
receiveSelectedWithMonitorAfter :: forall a r q. (Lifted IO q, HasCallStack, SetMember Process (Process q) r, Member Interrupts r, Show a) => ProcessId -> MessageSelector a -> Timeout -> Eff r (Either (Either ProcessDown TimerElapsed) a)
instance GHC.Classes.Eq Control.Eff.Concurrent.Process.Timer.TimerElapsed
instance GHC.Classes.Ord Control.Eff.Concurrent.Process.Timer.TimerElapsed
instance Control.DeepSeq.NFData Control.Eff.Concurrent.Process.Timer.TimerElapsed
instance GHC.Enum.Enum Control.Eff.Concurrent.Process.Timer.TimerReference
instance GHC.Real.Real Control.Eff.Concurrent.Process.Timer.TimerReference
instance GHC.Real.Integral Control.Eff.Concurrent.Process.Timer.TimerReference
instance GHC.Num.Num Control.Eff.Concurrent.Process.Timer.TimerReference
instance GHC.Classes.Eq Control.Eff.Concurrent.Process.Timer.TimerReference
instance GHC.Classes.Ord Control.Eff.Concurrent.Process.Timer.TimerReference
instance Control.DeepSeq.NFData Control.Eff.Concurrent.Process.Timer.TimerReference
instance GHC.Enum.Enum Control.Eff.Concurrent.Process.Timer.Timeout
instance GHC.Real.Real Control.Eff.Concurrent.Process.Timer.Timeout
instance GHC.Real.Integral Control.Eff.Concurrent.Process.Timer.Timeout
instance GHC.Num.Num Control.Eff.Concurrent.Process.Timer.Timeout
instance GHC.Classes.Eq Control.Eff.Concurrent.Process.Timer.Timeout
instance GHC.Classes.Ord Control.Eff.Concurrent.Process.Timer.Timeout
instance Control.DeepSeq.NFData Control.Eff.Concurrent.Process.Timer.Timeout
instance GHC.Show.Show Control.Eff.Concurrent.Process.Timer.TimerElapsed
instance GHC.Show.Show Control.Eff.Concurrent.Process.Timer.TimerReference
instance GHC.Show.Show Control.Eff.Concurrent.Process.Timer.Timeout
-- | Logging via extensible-effects
--
-- Logging consist of two effects:
--
-- -- exampleLogging :: IO () -- exampleLogging = -- runLift -- $ withLogging consoleLogWriter -- $ do -- logDebug "test 1.1" -- logError "test 1.2" -- censorLogs (prefixLogMessagesWith "NESTED: ") -- $ do -- addLogWriter debugTraceLogWriter -- $ setLogPredicate (\m -> (view lmMessage m) /= "not logged") -- $ do -- logInfo "not logged" -- logMsg "test 2.1" -- logWarning "test 2.2" -- logCritical "test 1.3" ---- --
-- exampleLogPredicate :: IO Int -- exampleLogPredicate = -- runLift -- $ withLogging consoleLogWriter -- $ do logMsg "test" -- setLogPredicate (\ msg -> case view lmMessage msg of -- 'O':'M':'G':_ -> True -- _ -> False) -- (do logMsg "this message will not be logged" -- logMsg "OMG logged" -- return 42) ---- -- In order to also delegate to the previous predicate, use -- modifyLogPredicate -- -- See Control.Eff.Log#LogPredicate setLogPredicate :: forall r b. (Member Logs r, HasCallStack) => LogPredicate -> Eff r b -> Eff r b -- | Change the LogPredicate. -- -- Other than setLogPredicate this function allows to include the -- previous predicate, too. -- -- For to discard all messages currently no satisfying the predicate and -- also all messages that are to long: -- --
-- modifyLogPredicate (previousPredicate msg -> previousPredicate msg && length (lmMessage msg) < 29 ) -- (do logMsg "this message will not be logged" -- logMsg "this message might be logged") ---- -- See Control.Eff.Log#LogPredicate modifyLogPredicate :: forall e b. (Member Logs e, HasCallStack) => (LogPredicate -> LogPredicate) -> Eff e b -> Eff e b -- | Get the current Logs filter/transformer function. -- -- See Control.Eff.Log#LogPredicate askLogPredicate :: forall e. Member Logs e => Eff e LogPredicate -- | Replace the current LogWriter. To add an additional log message -- consumer use addLogWriter setLogWriter :: forall h e a. LogsTo h e => LogWriter h -> Eff e a -> Eff e a -- | Combine the effects of a given LogWriter and the existing one. -- --
-- import Data.Text as T
-- import Data.Text.IO as T
--
-- exampleAddLogWriter :: IO ()
-- exampleAddLogWriter = go >>= T.putStrLn
-- where go = fmap (unlines . map renderLogMessageConsoleLog . snd)
-- $ runLift
-- $ runCaptureLogWriter
-- $ withLogging captureLogWriter
-- $ addLogWriter (mappingLogWriter (lmMessage %~ ("CAPTURED "++)) captureLogWriter)
-- $ addLogWriter (filteringLogWriter severeMessages (mappingLogWriter (lmMessage %~ ("TRACED "++)) debugTraceLogWriter))
-- $ do
-- logEmergency "test emergencySeverity 1"
-- logCritical "test criticalSeverity 2"
-- logAlert "test alertSeverity 3"
-- logError "test errorSeverity 4"
-- logWarning "test warningSeverity 5"
-- logInfo "test informationalSeverity 6"
-- logDebug "test debugSeverity 7"
-- severeMessages = view (lmSeverity . to (<= errorSeverity))
--
addLogWriter :: forall h e a. (HasCallStack, LogsTo h e, Monad h) => LogWriter h -> Eff e a -> Eff e a
-- | Change the current LogWriter.
modifyLogWriter :: forall h e a. LogsTo h e => (LogWriter h -> LogWriter h) -> Eff e a -> Eff e a
-- | Modify the the LogMessages written in the given sub-expression.
--
-- Note: This is equivalent to modifyLogWriter .
-- mappingLogWriter
censorLogs :: LogsTo h e => (LogMessage -> LogMessage) -> Eff e a -> Eff e a
-- | Modify the the LogMessages written in the given sub-expression,
-- as in censorLogs but with a effectful function.
--
-- Note: This is equivalent to modifyLogWriter .
-- mappingLogWriterM
censorLogsM :: (LogsTo h e, Monad h) => (LogMessage -> h LogMessage) -> Eff e a -> Eff e a
-- | This effect sends LogMessages and is a reader for a
-- LogPredicate.
--
-- Logs are sent via logMsg; for more information about log
-- predicates, see Control.Eff.Log#LogPredicate
--
-- This effect is handled via withLogging.
data Logs v
-- | A constraint alias for effects that requires a LogWriterReader,
-- as well as that the contained LogWriterReader has a
-- HandleLogWriter instance.
--
-- The requirements of this constraint are provided by:
--
-- -- exampleWithLogging :: IO () -- exampleWithLogging = -- runLift -- $ withLogging consoleLogWriter -- $ logDebug "Oh, hi there" --withLogging :: forall h e a. (Applicative h, LogsTo h (Logs : (LogWriterReader h : e))) => LogWriter h -> Eff (Logs : (LogWriterReader h : e)) a -> Eff e a -- | Handles the Logs and LogWriterReader effects. -- -- By default it uses the noOpLogWriter, but using -- setLogWriter the LogWriter can be replaced. -- -- This is like withLogging applied to noOpLogWriter -- -- Example: -- --
-- exampleWithSomeLogging :: () -- exampleWithSomeLogging = -- run -- $ withSomeLogging @PureLogWriter -- $ logDebug "Oh, hi there" --withSomeLogging :: forall h e a. (Applicative h, LogsTo h (Logs : (LogWriterReader h : e))) => Eff (Logs : (LogWriterReader h : e)) a -> Eff e a -- | Raw handling of the Logs effect. Exposed for custom extensions, -- if in doubt use withLogging. runLogs :: forall h e b. LogsTo h (Logs : e) => LogPredicate -> Eff (Logs : e) b -> Eff e b -- | Consume log messages. -- -- Exposed for custom extensions, if in doubt use withLogging. -- -- Respond to all LogMessages logged from the given action, up to -- any MonadBaseControl liftings. -- -- Note that all logging is done through logMsg and that means -- only messages passing the LogPredicate are received. -- -- The LogMessages are consumed once they are passed to the -- given callback function, previous respondToLogMessage -- invocations further up in the call stack will not get the messages -- anymore. -- -- Use interceptLogMessages if the messages shall be passed any -- previous handler. -- -- NOTE: The effects of this function are lost when using -- MonadBaseControl, MonadMask, MonadCatch and -- MonadThrow. -- -- In contrast the functions based on modifying the LogWriter, -- such as addLogWriter or censorLogs, are save to use in -- combination with the aforementioned liftings. respondToLogMessage :: forall r b. Member Logs r => (LogMessage -> Eff r ()) -> Eff r b -> Eff r b -- | Change the LogMessages using an effectful function. -- -- Exposed for custom extensions, if in doubt use withLogging. -- -- This differs from respondToLogMessage in that the intercepted -- messages will be written either way, albeit in altered form. -- -- NOTE: The effects of this function are lost when using -- MonadBaseControl, MonadMask, MonadCatch and -- MonadThrow. -- -- In contrast the functions based on modifying the LogWriter, -- such as addLogWriter or censorLogs, are save to use in -- combination with the aforementioned liftings. interceptLogMessages :: forall r b. Member Logs r => (LogMessage -> Eff r LogMessage) -> Eff r b -> Eff r b -- | Utilities to implement effectful server-loops. module Control.Eff.Concurrent.Protocol.EffectfulServer -- | A type class for effectful server loops. -- -- This type class serves as interface for other abstractions, for -- example process supervision -- -- The methods of this class handle Events Requests for -- Pdu instance. -- -- Instances can by index types for Pdu family directly, or -- indirectly via the ServerPdu type family. -- -- To builder servers serving multiple protocols, use the generic -- Pdu instances, for which EmbedProtocol instances exist, -- like 2-,3-,4-, or 5-tuple. class Server (a :: Type) (e :: [Type -> Type]) where { -- | The value that defines what is required to initiate a Server -- loop. data family Init a e; -- | The index type of the Events that this server processes. This -- is the first parameter to the Request and therefore of the -- Pdu family. type family ServerPdu a :: Type; -- | Effects of the implementation type family Effects a e :: [Type -> Type]; type ServerPdu a = a; type Effects a e = e; } -- | Return the ProcessTitle. -- -- Usually you should rely on the default implementation serverTitle :: Server a e => Init a e -> ProcessTitle -- | Return the ProcessTitle. -- -- Usually you should rely on the default implementation serverTitle :: (Server a e, Typeable (ServerPdu a)) => Init a e -> ProcessTitle -- | Process the effects of the implementation runEffects :: Server a e => Init a e -> Eff (Effects a e) x -> Eff e x -- | Process the effects of the implementation runEffects :: (Server a e, Effects a e ~ e) => Init a e -> Eff (Effects a e) x -> Eff e x -- | Update the Model based on the Event. onEvent :: Server a e => Init a e -> Event (ServerPdu a) -> Eff (Effects a e) () -- | Update the Model based on the Event. onEvent :: (Server a e, Show (Init a e), Member Logs (Effects a e)) => Init a e -> Event (ServerPdu a) -> Eff (Effects a e) () -- | Internal protocol to communicate incoming messages and other events to -- the instances of Server. -- -- Note that this is required to receive any kind of messages in -- protocolServerLoop. data Event a -- | A Synchronous message was received. If an implementation wants -- to delegate nested Pdus, it can contramap the reply -- Serializer such that the Reply received by the caller -- has the correct type. [OnCall] :: forall a r. (Tangible r, TangiblePdu a ( 'Synchronous r)) => Serializer (Reply a r) -> RequestOrigin a r -> Pdu a ( 'Synchronous r) -> Event a [OnCast] :: forall a. TangiblePdu a 'Asynchronous => Pdu a 'Asynchronous -> Event a [OnInterrupt] :: Interrupt 'Recoverable -> Event a [OnDown] :: ProcessDown -> Event a [OnTimeOut] :: TimerElapsed -> Event a [OnMessage] :: StrictDynamic -> Event a -- | Execute the server loop. start :: forall a q h. (Server a (InterruptableProcess q), Typeable a, Typeable (ServerPdu a), LogsTo h (InterruptableProcess q), SetMember Process (Process q) (Effects a (InterruptableProcess q)), Member Interrupts (Effects a (InterruptableProcess q)), HasCallStack) => Init a (InterruptableProcess q) -> Eff (InterruptableProcess q) (Endpoint (ServerPdu a)) -- | Execute the server loop. startLink :: forall a q h. (Typeable a, Typeable (ServerPdu a), Server a (InterruptableProcess q), LogsTo h (InterruptableProcess q), SetMember Process (Process q) (Effects a (InterruptableProcess q)), Member Interrupts (Effects a (InterruptableProcess q)), HasCallStack) => Init a (InterruptableProcess q) -> Eff (InterruptableProcess q) (Endpoint (ServerPdu a)) -- | Execute the server loop. protocolServerLoop :: forall q h a. (Server a (InterruptableProcess q), LogsTo h (InterruptableProcess q), SetMember Process (Process q) (Effects a (InterruptableProcess q)), Member Interrupts (Effects a (InterruptableProcess q)), Typeable a, Typeable (ServerPdu a)) => Init a (InterruptableProcess q) -> Eff (InterruptableProcess q) () -- | The constraints for a tangible GenServer instance. type TangibleGenServer tag eLoop e = (LogIo e, SetMember Process (Process e) eLoop, Member Interrupts eLoop, Typeable e, Typeable eLoop, Typeable tag) -- | Make a Server from a data record instead of type-class -- instance. -- -- Sometimes it is much more concise to create an inline server-loop. In -- those cases it might not be practical to go through all this type -- class boilerplate. -- -- In these cases specifying a server by from a set of callback functions -- seems much more appropriate. -- -- This is such a helper. The GenServer is a record with to -- callbacks, and a Server instance that simply invokes the given -- callbacks. -- -- Servers that are directly based on LogIo and -- InterruptableProcess effects. -- -- The name prefix Gen indicates the inspiration from Erlang's -- gen_server module. data GenServer tag eLoop e -- | The name/id of a GenServer for logging purposes. newtype GenServerId tag MkGenServerId :: Text -> GenServerId tag [_fromGenServerId] :: GenServerId tag -> Text -- | Create a GenServer. -- -- This requires the callback for Events, a initial Model -- and a GenServerId. -- -- There must be a GenServerProtocol instance. -- -- This is Haskell, so if this functions is partially applied to some -- Event callback, you get a function back, that generates -- Inits from GenServerIds, like a factory genServer :: forall tag eLoop e. (HasCallStack, TangibleGenServer tag eLoop e, Server (GenServer tag eLoop e) (InterruptableProcess e)) => (forall x. GenServerId tag -> Eff eLoop x -> Eff (InterruptableProcess e) x) -> (GenServerId tag -> Event tag -> Eff eLoop ()) -> GenServerId tag -> Init (GenServer tag eLoop e) (InterruptableProcess e) -- | Wraps the source ProcessId and a unique identifier for a -- Call. data RequestOrigin (proto :: Type) reply RequestOrigin :: !ProcessId -> !Int -> RequestOrigin reply [_requestOriginPid] :: RequestOrigin reply -> !ProcessId [_requestOriginCallRef] :: RequestOrigin reply -> !Int -- | The wrapper around replies to Calls. data Reply protocol reply [Reply] :: Tangible reply => {_replyTo :: RequestOrigin protocol reply, _replyValue :: reply} -> Reply protocol reply -- | Send a Reply to a Call. -- -- The reply will be deeply evaluated to rnf. -- -- To send replies for EmbedProtocol instances use -- embedReplySerializer. sendReply :: (SetMember Process (Process q) eff, Member Interrupts eff, Tangible reply, Typeable protocol) => Serializer (Reply protocol reply) -> RequestOrigin protocol reply -> reply -> Eff eff () instance forall k (tag :: k). Data.String.IsString (Control.Eff.Concurrent.Protocol.EffectfulServer.GenServerId tag) instance forall k (tag :: k). GHC.Classes.Eq (Control.Eff.Concurrent.Protocol.EffectfulServer.GenServerId tag) instance forall k (tag :: k). GHC.Classes.Ord (Control.Eff.Concurrent.Protocol.EffectfulServer.GenServerId tag) instance forall k (tag :: k). Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.EffectfulServer.GenServerId tag) instance forall k (tag :: k). (Data.Typeable.Internal.Typeable k, Data.Typeable.Internal.Typeable tag) => GHC.Show.Show (Control.Eff.Concurrent.Protocol.EffectfulServer.GenServerId tag) instance Control.Eff.Concurrent.Protocol.EffectfulServer.TangibleGenServer tag eLoop e => Control.Eff.Concurrent.Protocol.EffectfulServer.Server (Control.Eff.Concurrent.Protocol.EffectfulServer.GenServer tag eLoop e) (Control.Eff.Concurrent.Process.InterruptableProcess e) instance Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.EffectfulServer.Init (Control.Eff.Concurrent.Protocol.EffectfulServer.GenServer tag eLoop e) (Control.Eff.Concurrent.Process.InterruptableProcess e)) instance Data.Typeable.Internal.Typeable tag => GHC.Show.Show (Control.Eff.Concurrent.Protocol.EffectfulServer.Init (Control.Eff.Concurrent.Protocol.EffectfulServer.GenServer tag eLoop e) (Control.Eff.Concurrent.Process.InterruptableProcess e)) instance GHC.Show.Show (Control.Eff.Concurrent.Protocol.EffectfulServer.Event a) instance Control.DeepSeq.NFData a => Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.EffectfulServer.Event a) -- | Utilities to implement server-loops with builtin state and -- TEA-like naming. module Control.Eff.Concurrent.Protocol.StatefulServer -- | A type class for server loops. -- -- This type class serves as interface for other abstractions, for -- example process supervision -- -- The methods of this class handle Events Requests for -- Pdu instance. -- -- Instances can by index types for Pdu family directly, or -- indirectly via the ServerPdu type family. -- -- To builder servers serving multiple protocols, use the generic -- Pdu instances, for which EmbedProtocol instances exist, -- like 2-,3-,4-, or 5-tuple. -- -- The naming is inspired by The Elm Architecture, without the -- view callback. -- -- This class is based on -- Control.Eff.Concurrent.Protocol.EffectfulServer and adds a -- default State and Reader effect. class (Typeable (Protocol a)) => Server (a :: Type) q where { -- | The value that defines what is required to initiate a Server -- loop. data family StartArgument a q; -- | The index type of the Events that this server processes. This -- is the first parameter to the Request and therefore of the -- Pdu family. type family Protocol a :: Type; -- | Type of the model data, given to every invocation of -- update via the ModelState effect. The model of a -- server loop is changed through incoming Events. It is -- initially calculated by setup. type family Model a :: Type; -- | Type of read-only state. type family Settings a :: Type; type Protocol a = a; type Model a = (); type Settings a = (); } -- | Return an initial Model and Settings setup :: Server a q => StartArgument a q -> Eff (InterruptableProcess q) (Model a, Settings a) -- | Return an initial Model and Settings setup :: (Server a q, Default (Model a), Default (Settings a)) => StartArgument a q -> Eff (InterruptableProcess q) (Model a, Settings a) -- | Update the Model based on the Event. update :: Server a q => StartArgument a q -> Event (Protocol a) -> Eff (ModelState a : (SettingsReader a : InterruptableProcess q)) () -- | Execute the server loop. start :: forall a q h. (HasCallStack, Typeable a, LogsTo h (InterruptableProcess q), Server (Stateful a) (InterruptableProcess q), Server a q) => StartArgument a q -> Eff (InterruptableProcess q) (Endpoint (Protocol a)) -- | Execute the server loop. startLink :: forall a q h. (HasCallStack, Typeable a, LogsTo h (InterruptableProcess q), Server (Stateful a) (InterruptableProcess q), Server a q) => StartArgument a q -> Eff (InterruptableProcess q) (Endpoint (Protocol a)) -- | The Effect type of mutable Model in a Server -- instance. type ModelState a = State (Model a) -- | Modify the Model of a Server. modifyModel :: forall a e. Member (ModelState a) e => (Model a -> Model a) -> Eff e () -- | Modify the Model of a Server and return the old value. getAndModifyModel :: forall a e. Member (ModelState a) e => (Model a -> Model a) -> Eff e (Model a) -- | Modify the Model of a Server and return the new value. modifyAndGetModel :: forall a e. Member (ModelState a) e => (Model a -> Model a) -> Eff e (Model a) -- | Return the Model of a Server. getModel :: forall a e. Member (ModelState a) e => Eff e (Model a) -- | Overwrite the Model of a Server. putModel :: forall a e. Member (ModelState a) e => Model a -> Eff e () -- | Overwrite the Model of a Server, return the old value. getAndPutModel :: forall a e. Member (ModelState a) e => Model a -> Eff e (Model a) -- | Return a element selected by a Lens of the Model of a -- Server. useModel :: forall a b e. Member (ModelState a) e => Getting b (Model a) b -> Eff e b -- | Run an action that modifies portions of the Model of a -- Server defined by the given Lens. zoomModel :: forall a b c e. Member (ModelState a) e => Lens' (Model a) b -> Eff (State b : e) c -> Eff e c -- | The Effect type of readonly Settings in a Server -- instance. type SettingsReader a = Reader (Settings a) -- | Return the read-only Settings of a Server askSettings :: forall a e. Member (SettingsReader a) e => Eff e (Settings a) -- | Return the read-only Settings of a Server as viewed -- through a Lens viewSettings :: forall a b e. Member (SettingsReader a) e => Getting b (Settings a) b -> Eff e b -- | Internal protocol to communicate incoming messages and other events to -- the instances of Server. -- -- Note that this is required to receive any kind of messages in -- protocolServerLoop. data Event a -- | A Synchronous message was received. If an implementation wants -- to delegate nested Pdus, it can contramap the reply -- Serializer such that the Reply received by the caller -- has the correct type. [OnCall] :: forall a r. (Tangible r, TangiblePdu a ( 'Synchronous r)) => Serializer (Reply a r) -> RequestOrigin a r -> Pdu a ( 'Synchronous r) -> Event a [OnCast] :: forall a. TangiblePdu a 'Asynchronous => Pdu a 'Asynchronous -> Event a [OnInterrupt] :: Interrupt 'Recoverable -> Event a [OnDown] :: ProcessDown -> Event a [OnTimeOut] :: TimerElapsed -> Event a [OnMessage] :: StrictDynamic -> Event a -- | Wraps the source ProcessId and a unique identifier for a -- Call. data RequestOrigin (proto :: Type) reply RequestOrigin :: !ProcessId -> !Int -> RequestOrigin reply [_requestOriginPid] :: RequestOrigin reply -> !ProcessId [_requestOriginCallRef] :: RequestOrigin reply -> !Int -- | The wrapper around replies to Calls. data Reply protocol reply [Reply] :: Tangible reply => {_replyTo :: RequestOrigin protocol reply, _replyValue :: reply} -> Reply protocol reply -- | Send a Reply to a Call. -- -- The reply will be deeply evaluated to rnf. -- -- To send replies for EmbedProtocol instances use -- embedReplySerializer. sendReply :: (SetMember Process (Process q) eff, Member Interrupts eff, Tangible reply, Typeable protocol) => Serializer (Reply protocol reply) -> RequestOrigin protocol reply -> reply -> Eff eff () instance Control.Eff.Concurrent.Protocol.StatefulServer.Server a q => Control.Eff.Concurrent.Protocol.EffectfulServer.Server (Control.Eff.Concurrent.Protocol.StatefulServer.Stateful a) (Control.Eff.Concurrent.Process.InterruptableProcess q) -- | Functions for protocol clients. -- -- This modules is required to write clients that sendPdus. module Control.Eff.Concurrent.Protocol.Client -- | Send a request Pdu that has no reply and return immediately. -- -- The type signature enforces that the corresponding Pdu clause -- is Asynchronous. The operation never fails, if it is important -- to know if the message was delivered, use call instead. -- -- The message will be reduced to normal form (rnf) in the -- caller process. cast :: forall o' o r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r, TangiblePdu o' 'Asynchronous, TangiblePdu o 'Asynchronous, EmbedProtocol o' o) => Endpoint o' -> Pdu o 'Asynchronous -> Eff r () -- | Send a request Pdu and wait for the server to return a result -- value. -- -- The type signature enforces that the corresponding Pdu clause -- is Synchronous. -- -- Always prefer callWithTimeout over call call :: forall result protocol' protocol r q. (SetMember Process (Process q) r, Member Interrupts r, TangiblePdu protocol' ( 'Synchronous result), TangiblePdu protocol ( 'Synchronous result), EmbedProtocol protocol' protocol, Tangible result, HasCallStack) => Endpoint protocol' -> Pdu protocol ( 'Synchronous result) -> Eff r result -- | Send an request Pdu and wait for the server to return a result -- value. -- -- The type signature enforces that the corresponding Pdu clause -- is Synchronous. -- -- If the server that was called dies, this function interrupts the -- process with ProcessDown. If the server takes longer to reply -- than the given timeout, this function interrupts the process with -- TimeoutInterrupt. -- -- Always prefer this function over call callWithTimeout :: forall result protocol' protocol r q. (SetMember Process (Process q) r, Member Interrupts r, TangiblePdu protocol' ( 'Synchronous result), TangiblePdu protocol ( 'Synchronous result), EmbedProtocol protocol' protocol, Tangible result, Member Logs r, Lifted IO q, Lifted IO r, HasCallStack) => Endpoint protocol' -> Pdu protocol ( 'Synchronous result) -> Timeout -> Eff r result -- | Like cast but take the Endpoint from the reader provided -- by runEndpointReader. castEndpointReader :: forall o r q. (ServesProtocol o r q, HasCallStack, Member Interrupts r, TangiblePdu o 'Asynchronous) => Pdu o 'Asynchronous -> Eff r () -- | Like call but take the Endpoint from the reader provided -- by runEndpointReader. callEndpointReader :: forall reply o r q. (ServesProtocol o r q, HasCallStack, Tangible reply, TangiblePdu o ( 'Synchronous reply), Member Interrupts r) => Pdu o ( 'Synchronous reply) -> Eff r reply -- | Instead of passing around a Endpoint value and passing to -- functions like cast or call, a Endpoint can -- provided by a Reader effect, if there is only a single -- server for a given Pdu instance. This type alias is -- convenience to express that an effect has Process and a reader -- for a Endpoint. type ServesProtocol o r q = (Typeable o, SetMember Process (Process q) r, Member (EndpointReader o) r) -- | The reader effect for ProcessIds for Pdus, see -- runEndpointReader type EndpointReader o = Reader (Endpoint o) -- | Get the Endpoint registered with runEndpointReader. askEndpoint :: Member (EndpointReader o) e => Eff e (Endpoint o) -- | Run a reader effect that contains the one server handling a -- specific Pdu instance. runEndpointReader :: HasCallStack => Endpoint o -> Eff (EndpointReader o : r) a -> Eff r a -- | A process supervisor spawns and monitors child processes. -- -- The child processes are mapped to symbolic identifier values: -- Child-IDs. -- -- This is the barest, most minimal version of a supervisor. Children can -- be started, but not restarted. -- -- Children can efficiently be looked-up by an id-value, and when the -- supervisor is shutdown, all children will be shutdown these are -- actually all the features of this supervisor implementation. -- -- Also, this minimalist supervisor only knows how to spawn a single kind -- of child process. -- -- When a supervisor spawns a new child process, it expects the child -- process to return a ProcessId. The supervisor will -- monitor the child process. -- -- This is in stark contrast to how Erlang/OTP handles things; In the OTP -- Supervisor, the child has to link to the parent. This allows the child -- spec to be more flexible in that no pid has to be passed from -- the child start function to the supervisor process, and also, a child -- may break free from the supervisor by unlinking. -- -- Now while this seems nice at first, this might actually cause -- surprising results, since it is usually expected that stopping a -- supervisor also stops the children, or that a child exit shows up in -- the logging originating from the former supervisor. -- -- The approach here is to allow any child to link to the supervisor to -- realize when the supervisor was violently killed, and otherwise give -- the child no chance to unlink itself from its supervisor. -- -- This module is far simpler than the Erlang/OTP counter part, of a -- simple_one_for_one supervisor. -- -- The future of this supervisor might not be a-lot more than it -- currently is. The ability to restart processes might be implemented -- outside of this supervisor module. -- -- One way to do that is to implement the restart logic in a separate -- module, since the child-id can be reused when a child exits. module Control.Eff.Concurrent.Protocol.Supervisor -- | The index type of Server supervisors. -- -- A Sup p manages the life cycle of the processes, -- running the Server p methods of that specific type. -- -- The supervisor maps an identifier value of type ChildId -- p to an Endpoint p. data Sup p -- | The type of value used to index running Server processes -- managed by a Sup. -- -- Note, that the type you provide must be Tangible. type family ChildId p -- | The value that defines what is required to initiate a Server -- loop. data family StartArgument a q supConfigChildStopTimeout :: StartArgument (Sup p) q -> Timeout -- | Runtime-Errors occurring when spawning child-processes. data SpawnErr p AlreadyStarted :: ChildId p -> Endpoint (Protocol p) -> SpawnErr p -- | Start and link a new supervisor process with the given -- SpawnFununction. -- -- To spawn new child processes use spawnChild. startSupervisor :: forall p e. (HasCallStack, LogsTo IO (InterruptableProcess e), Lifted IO e, TangibleSup p, Server (Sup p) e) => StartArgument (Sup p) e -> Eff (InterruptableProcess e) (Endpoint (Sup p)) -- | Stop the supervisor and shutdown all processes. -- -- Block until the supervisor has finished. stopSupervisor :: (HasCallStack, Member Interrupts e, SetMember Process (Process q0) e, Member Logs e, Lifted IO e, TangibleSup p) => Endpoint (Sup p) -> Eff e () -- | Check if a supervisor process is still alive. isSupervisorAlive :: forall p q0 e. (HasCallStack, Member Interrupts e, Member Logs e, Typeable p, SetMember Process (Process q0) e) => Endpoint (Sup p) -> Eff e Bool -- | Monitor a supervisor process. monitorSupervisor :: forall p q0 e. (HasCallStack, Member Interrupts e, Member Logs e, SetMember Process (Process q0) e, TangibleSup p) => Endpoint (Sup p) -> Eff e MonitorReference -- | Return a Text describing the current state of the supervisor. getDiagnosticInfo :: forall p e q0. (HasCallStack, Member Interrupts e, SetMember Process (Process q0) e, TangibleSup p) => Endpoint (Sup p) -> Eff e Text -- | Start, link and monitor a new child process using the -- SpawnFun passed to startSupervisor. spawnChild :: forall p q0 e. (HasCallStack, Member Interrupts e, Member Logs e, SetMember Process (Process q0) e, TangibleSup p, Typeable (Protocol p)) => Endpoint (Sup p) -> ChildId p -> Eff e (Either (SpawnErr p) (Endpoint (Protocol p))) -- | Lookup the given child-id and return the output value of the -- SpawnFun if the client process exists. lookupChild :: forall p e q0. (HasCallStack, Member Interrupts e, Member Logs e, SetMember Process (Process q0) e, TangibleSup p, Typeable (Protocol p)) => Endpoint (Sup p) -> ChildId p -> Eff e (Maybe (Endpoint (Protocol p))) -- | Stop a child process, and block until the child has exited. -- -- Return True if a process with that ID was found, False -- if no process with the given ID was running. stopChild :: forall p e q0. (HasCallStack, Member Interrupts e, Member Logs e, SetMember Process (Process q0) e, TangibleSup p) => Endpoint (Sup p) -> ChildId p -> Eff e Bool instance GHC.Generics.Generic (Control.Eff.Concurrent.Protocol.Supervisor.SpawnErr p) instance GHC.Classes.Eq (Control.Eff.Concurrent.Protocol.Supervisor.ChildId p) => GHC.Classes.Eq (Control.Eff.Concurrent.Protocol.Supervisor.SpawnErr p) instance GHC.Classes.Ord (Control.Eff.Concurrent.Protocol.Supervisor.ChildId p) => GHC.Classes.Ord (Control.Eff.Concurrent.Protocol.Supervisor.SpawnErr p) instance (Data.Typeable.Internal.Typeable (Control.Eff.Concurrent.Protocol.StatefulServer.Protocol p), GHC.Show.Show (Control.Eff.Concurrent.Protocol.Supervisor.ChildId p)) => GHC.Show.Show (Control.Eff.Concurrent.Protocol.Supervisor.SpawnErr p) instance (Control.Eff.Internal.Lifted GHC.Types.IO q, Control.Eff.Log.Handler.LogsTo GHC.Types.IO q, Control.Eff.Concurrent.Protocol.Supervisor.TangibleSup p, Control.Eff.Concurrent.Protocol.Tangible (Control.Eff.Concurrent.Protocol.Supervisor.ChildId p), Control.Eff.Concurrent.Protocol.StatefulServer.Server p q) => Control.Eff.Concurrent.Protocol.StatefulServer.Server (Control.Eff.Concurrent.Protocol.Supervisor.Sup p) q instance Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Supervisor.ChildId p) => Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Supervisor.SpawnErr p) instance GHC.Show.Show (Control.Eff.Concurrent.Protocol.Supervisor.ChildId p) => GHC.Show.Show (Control.Eff.Concurrent.Protocol.Pdu (Control.Eff.Concurrent.Protocol.Supervisor.Sup p) ('Control.Eff.Concurrent.Protocol.Synchronous r)) instance Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Supervisor.ChildId p) => Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Pdu (Control.Eff.Concurrent.Protocol.Supervisor.Sup p) ('Control.Eff.Concurrent.Protocol.Synchronous r)) -- | Observer Effects -- -- This module supports the implementation of observers and observables. -- Expected use case is event propagation. module Control.Eff.Concurrent.Protocol.Observer -- | Describes a process that observes another via Asynchronous -- Pdu messages. -- -- An observer consists of a filter and a process id. The filter converts -- an observation to a message understood by the observer process, and -- the ProcessId is used to send the message. data Observer o [Observer] :: (Tangible o, TangiblePdu p 'Asynchronous, Tangible (Endpoint p), Typeable p) => (o -> Maybe (Pdu p 'Asynchronous)) -> Endpoint p -> Observer o -- | The constraints on the type parameters to an Observer type TangibleObserver o = (Tangible o, TangiblePdu (Observer o) 'Asynchronous) -- | This data family defines the **protocol data units**(PDU) of a -- protocol. -- -- A Protocol in the sense of a communication interface description -- between processes. -- -- The first parameter is usually a user defined type that identifies the -- protocol that uses the Pdus are. It maybe a phantom -- type. -- -- The second parameter specifies if a specific constructor of an -- (GADT-like) Pdu instance is Synchronous, i.e. returns -- a result and blocks the caller or if it is Asynchronous -- -- Example: -- --
-- data BookShop deriving Typeable
--
-- data instance Pdu BookShop r where
-- RentBook :: BookId -> Pdu BookShop ('Synchronous (Either RentalError RentalId))
-- BringBack :: RentalId -> Pdu BookShop 'Asynchronous
--
-- type BookId = Int
-- type RentalId = Int
-- type RentalError = String
--
data family Pdu (protocol :: Type) (reply :: Synchronicity)
-- | And an Observer to the set of recipients for all observations
-- reported by observed. Note that the observers are keyed by the
-- observing process, i.e. a previous entry for the process contained in
-- the Observer is overwritten. If you want multiple entries for a
-- single process, just combine several filter functions.
registerObserver :: (SetMember Process (Process q) r, HasCallStack, Member Interrupts r, TangibleObserver o, EmbedProtocol x (ObserverRegistry o), TangiblePdu x 'Asynchronous) => Observer o -> Endpoint x -> Eff r ()
-- | Send the ForgetObserver message
forgetObserver :: (SetMember Process (Process q) r, HasCallStack, Member Interrupts r, Typeable o, NFData o, EmbedProtocol x (ObserverRegistry o), TangiblePdu x 'Asynchronous) => Observer o -> Endpoint x -> Eff r ()
-- | Based on the Pdu instance for Observer this simplified
-- writing a callback handler for observations. In order to register to
-- and ObserverRegistry use toObserver.
handleObservations :: (HasCallStack, Typeable o, SetMember Process (Process q) r, NFData (Observer o)) => (o -> Eff r ()) -> Pdu (Observer o) 'Asynchronous -> Eff r ()
-- | Use a Endpoint as an Observer for
-- handleObservations.
toObserver :: TangibleObserver o => Endpoint (Observer o) -> Observer o
-- | Create an Observer that conditionally accepts all observations
-- of the given type and applies the given function to them; the function
-- takes an observation and returns an Pdu cast that the observer
-- server is compatible to.
toObserverFor :: (TangibleObserver o, Typeable a, TangiblePdu a 'Asynchronous) => (o -> Pdu a 'Asynchronous) -> Endpoint a -> Observer o
-- | A protocol for managing Observers, encompassing registration
-- and de-registration of Observers.
data ObserverRegistry o
-- | Alias for the effect that contains the observers managed by
-- manageObservers
type ObserverState o = State (Observers o)
-- | Internal state for manageObservers
data Observers o
-- | The empty ObserverState
emptyObservers :: Observers o
-- | Provide the implementation for the ObserverRegistry Protocol,
-- this handled RegisterObserver and ForgetObserver
-- messages. It also adds the ObserverState constraint to the
-- effect list.
handleObserverRegistration :: forall o q r. (HasCallStack, Typeable o, SetMember Process (Process q) r, Member (ObserverState o) r, Member Logs r) => Pdu (ObserverRegistry o) 'Asynchronous -> Eff r ()
-- | Keep track of registered Observers.
--
-- Handle the ObserverState introduced by
-- handleObserverRegistration.
manageObservers :: Eff (ObserverState o : r) a -> Eff r a
-- | Report an observation to all observers. The process needs to
-- manageObservers and to handleObserverRegistration.
observed :: forall o r q. (SetMember Process (Process q) r, Member (ObserverState o) r, Member Interrupts r, TangibleObserver o) => o -> Eff r ()
instance Control.DeepSeq.NFData o => Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Observer.Observers o)
instance GHC.Show.Show (Control.Eff.Concurrent.Protocol.Observer.Observers o)
instance GHC.Classes.Ord (Control.Eff.Concurrent.Protocol.Observer.Observers o)
instance GHC.Classes.Eq (Control.Eff.Concurrent.Protocol.Observer.Observers o)
instance forall k (o :: k) (r :: Control.Eff.Concurrent.Protocol.Synchronicity). Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Pdu (Control.Eff.Concurrent.Protocol.Observer.ObserverRegistry o) r)
instance forall k (o :: k) (r :: Control.Eff.Concurrent.Protocol.Synchronicity). GHC.Show.Show (Control.Eff.Concurrent.Protocol.Pdu (Control.Eff.Concurrent.Protocol.Observer.ObserverRegistry o) r)
instance Control.DeepSeq.NFData o => Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Observer.Observer o)
instance GHC.Show.Show (Control.Eff.Concurrent.Protocol.Observer.Observer o)
instance GHC.Classes.Ord (Control.Eff.Concurrent.Protocol.Observer.Observer o)
instance GHC.Classes.Eq (Control.Eff.Concurrent.Protocol.Observer.Observer o)
instance Control.DeepSeq.NFData o => Control.DeepSeq.NFData (Control.Eff.Concurrent.Protocol.Pdu (Control.Eff.Concurrent.Protocol.Observer.Observer o) 'Control.Eff.Concurrent.Protocol.Asynchronous)
instance GHC.Show.Show o => GHC.Show.Show (Control.Eff.Concurrent.Protocol.Pdu (Control.Eff.Concurrent.Protocol.Observer.Observer o) r)
-- | A small process to capture and _share_ observation's by enqueueing
-- them into an STM TBQueue.
module Control.Eff.Concurrent.Protocol.Observer.Queue
-- | Contains a TBQueue capturing observations. See
-- spawnLinkObservationQueueWriter, readObservationQueue.
newtype ObservationQueue a
ObservationQueue :: TBQueue a -> ObservationQueue a
-- | A Reader for an ObservationQueue.
type ObservationQueueReader a = Reader (ObservationQueue a)
-- | Read queued observations captured and enqueued in the shared
-- TBQueue by spawnLinkObservationQueueWriter. This blocks
-- until something was captured or an interrupt or exceptions was thrown.
-- For a non-blocking variant use tryReadObservationQueue or
-- flushObservationQueue.
readObservationQueue :: forall o r. (Member (ObservationQueueReader o) r, HasCallStack, MonadIO (Eff r), Typeable o, Member Logs r) => Eff r o
-- | Read queued observations captured and enqueued in the shared
-- TBQueue by spawnLinkObservationQueueWriter. Return the
-- oldest enqueued observation immediately or Nothing if the queue
-- is empty. Use readObservationQueue to block until an
-- observation is observed.
tryReadObservationQueue :: forall o r. (Member (ObservationQueueReader o) r, HasCallStack, MonadIO (Eff r), Typeable o, Member Logs r) => Eff r (Maybe o)
-- | Read at once all currently queued observations captured and enqueued
-- in the shared TBQueue by
-- spawnLinkObservationQueueWriter. This returns immediately all
-- currently enqueued observations. For a blocking variant use
-- readObservationQueue.
flushObservationQueue :: forall o r. (Member (ObservationQueueReader o) r, HasCallStack, MonadIO (Eff r), Typeable o, Member Logs r) => Eff r [o]
-- | Create a mutable queue for observations. Use
-- spawnLinkObservationQueueWriter for a simple way to get a
-- process that enqueues all observations.
--
-- -- withObservationQueue 100 $ do -- q <- ask @(ObservationQueueReader TestEvent) -- wq <- spawnLinkObservationQueueWriter q -- registerObserver wq testServer -- ... -- cast testServer DoSomething -- evt <- readObservationQueue @TestEvent -- ... --withObservationQueue :: forall o b e len. (HasCallStack, Typeable o, Show o, Member Logs e, Lifted IO e, Integral len, Member Interrupts e) => len -> Eff (ObservationQueueReader o : e) b -> Eff e b -- | Spawn a process that can be used as an Observer that enqueues -- the observations into an ObservationQueue. See -- withObservationQueue for an example. -- -- The observations can be obtained by readObservationQueue. All -- observations are captured up to the queue size limit, such that the -- first message received will be first message returned by -- readObservationQueue. spawnLinkObservationQueueWriter :: forall o q h. (TangibleObserver o, TangiblePdu (Observer o) 'Asynchronous, Member Logs q, Lifted IO q, LogsTo h (InterruptableProcess q), HasCallStack) => ObservationQueue o -> Eff (InterruptableProcess q) (Observer o) instance (Control.Eff.Concurrent.Protocol.Observer.TangibleObserver o, Control.Eff.Concurrent.Protocol.TangiblePdu (Control.Eff.Concurrent.Protocol.Observer.Observer o) 'Control.Eff.Concurrent.Protocol.Asynchronous, Control.Eff.Internal.Lifted GHC.Types.IO q, Data.OpenUnion.Member Control.Eff.Log.Handler.Logs q) => Control.Eff.Concurrent.Protocol.StatefulServer.Server (Control.Eff.Concurrent.Protocol.Observer.Queue.ObservationQueue o) q -- | This module provides support for executing Process actions from -- IO. -- -- One use case is interacting with processes from the REPL, e.g.: -- --
-- >>> import Control.Eff.Concurrent.Process.SingleThreadedScheduler (defaultMain) ---- --
-- >>> import Control.Eff.Loop ---- --
-- >>> import Data.Dynamic ---- --
-- >>> import Data.Maybe ---- --
-- >>> s <- forkInteractiveScheduler Control.Eff.Concurrent.Process.SingleThreadedScheduler.defaultMain ---- --
-- >>> fooPid <- submit s (spawn (foreverCheap (receiveAnyMessage SP >>= (logMsg . fromMaybe "Huh!??" . fromDynamic)))) ---- --
-- >>> fooPid -- <0.1.0> ---- --
-- >>> submit s (sendMessageAs SP fooPid "test") -- test ---- --
-- >>> submit s (sendShutdown SP fooPid) --module Control.Eff.Concurrent.Process.Interactive -- | Contains the communication channels to interact with a scheduler -- running in its' own thread. data SchedulerSession r -- | Fork a scheduler with a process that communicates with it via -- MVar, which is also the reason for the Lift IO -- constraint. forkInteractiveScheduler :: forall r. SetMember Lift (Lift IO) r => (Eff (InterruptableProcess r) () -> IO ()) -> IO (SchedulerSession r) -- | Exit the scheduler immediately using an asynchronous exception. killInteractiveScheduler :: SchedulerSession r -> IO () -- | Send a Process effect to the main process of a scheduler, this -- blocks until the effect is executed. submit :: forall r a. SetMember Lift (Lift IO) r => SchedulerSession r -> Eff (InterruptableProcess r) a -> IO a -- | Combination of submit and cast. submitCast :: forall o r. (SetMember Lift (Lift IO) r, TangiblePdu o 'Asynchronous, Member Interrupts r) => SchedulerSession r -> Endpoint o -> Pdu o 'Asynchronous -> IO () -- | Combination of submit and cast. submitCall :: forall o q r. (SetMember Lift (Lift IO) r, Member Interrupts r, TangiblePdu o ( 'Synchronous q), Tangible q) => SchedulerSession r -> Endpoint o -> Pdu o ( 'Synchronous q) -> IO q -- | Capture LogMessages to a Writer. -- -- See exampleLogCapture module Control.Eff.LogWriter.Capture -- | A LogWriter monad that provides pure logging by capturing via -- the Writer effect. -- -- See exampleLogCapture captureLogWriter :: LogWriter CaptureLogs -- | A LogWriter monad that provides pure logging by capturing via -- the Writer effect. newtype CaptureLogs a MkCaptureLogs :: Eff '[CaptureLogWriter] a -> CaptureLogs a [unCaptureLogs] :: CaptureLogs a -> Eff '[CaptureLogWriter] a -- | Alias for the Writer that contains the captured -- LogMessages from CaptureLogs. type CaptureLogWriter = Writer LogMessage -- | Run a Writer for LogMessages. -- -- Such a Writer is needed to handle CaptureLogWriter runCaptureLogWriter :: Eff (CaptureLogWriter : e) a -> Eff e (a, [LogMessage]) instance GHC.Base.Monad Control.Eff.LogWriter.Capture.CaptureLogs instance GHC.Base.Applicative Control.Eff.LogWriter.Capture.CaptureLogs instance GHC.Base.Functor Control.Eff.LogWriter.Capture.CaptureLogs instance Data.OpenUnion.Member Control.Eff.LogWriter.Capture.CaptureLogWriter e => Control.Eff.Log.Writer.HandleLogWriter Control.Eff.LogWriter.Capture.CaptureLogs e -- | Functions for generic, IO-based LogWriters. -- -- This module is more low-level than the others in this directory. module Control.Eff.LogWriter.IO -- | A LogWriter that uses an IO action to write the message. -- -- This is just an alias for MkLogWriter but with IO as -- parameter. This reduces the need to apply something to the extra type -- argument @IO. -- -- Example use cases for this function are the consoleLogWriter -- and the ioHandleLogWriter. mkLogWriterIO :: HasCallStack => (LogMessage -> IO ()) -> LogWriter IO -- | A LogWriter that renders LogMessages to strings via -- renderLogMessageConsoleLog and prints them to an Handle -- using hPutStrLn. ioHandleLogWriter :: HasCallStack => Handle -> LogWriter IO -- | Decorate an IO based LogWriter to fill out these fields in -- LogMessages: -- --
-- exampleWithIoLogging :: IO () -- exampleWithIoLogging = -- runLift -- $ withIoLogging debugTraceLogWriter -- "my-app" -- local7 -- (lmSeverityIsAtLeast informationalSeverity) -- $ logInfo "Oh, hi there" --withIoLogging :: SetMember Lift (Lift IO) e => LogWriter IO -> Text -> Facility -> LogPredicate -> Eff (Logs : (LogWriterReader IO : e)) a -> Eff e a -- | The concrete list of Effects for logging with an IO based -- LogWriter, and a LogWriterReader. type LoggingAndIo = '[Logs, LogWriterReader IO, Lift IO] -- | Render a LogMessage but set the timestamp and thread id fields. printLogMessage :: LogMessage -> IO () -- | This helps to setup logging to a file. module Control.Eff.LogWriter.File -- | Enable logging to a file, with some LogMessage fields preset as -- described in withIoLogging. -- -- If the file or its directory does not exist, it will be created. -- -- Example: -- --
-- exampleWithFileLogging :: IO () -- exampleWithFileLogging = -- runLift -- $ withFileLogging "/var/log/my-app.log" "my-app" local7 allLogMessages -- $ logInfo "Oh, hi there" ---- -- To vary the LogWriter use withIoLogging. withFileLogging :: (Lifted IO e, MonadBaseControl IO (Eff e)) => FilePath -> Text -> Facility -> LogPredicate -> Eff (Logs : (LogWriterReader IO : e)) a -> Eff e a -- | Enable logging to a file. -- -- If the file or its directory does not exist, it will be created. -- Example: -- --
-- exampleWithFileLogWriter :: IO () -- exampleWithFileLogWriter = -- runLift -- $ withSomeLogging @IO -- $ withFileLogWriter "test.log" -- $ logInfo "Oh, hi there" --withFileLogWriter :: (Lifted IO e, LogsTo IO e, MonadBaseControl IO (Eff e)) => FilePath -> Eff e b -> Eff e b -- | This helps to setup logging via Debug.Trace. module Control.Eff.LogWriter.DebugTrace -- | Enable logging via traceM using the debugTraceLogWriter. -- The logging monad type can be any type with a Monad -- instance. -- -- Log messages are rendered using renderLogMessageConsoleLog. -- -- Example: -- --
-- exampleWithTraceLogWriter :: IO () -- exampleWithTraceLogWriter = -- runLift -- $ withSomeLogging @IO -- $ withTraceLogWriter -- $ logInfo "Oh, hi there" --withTraceLogWriter :: forall h e a. (Monad h, LogsTo h e) => Eff e a -> Eff e a -- | Enable logging via traceM using the debugTraceLogWriter, -- with some LogMessage fields preset as in withIoLogging. -- -- Log messages are rendered using renderLogMessageConsoleLog. -- -- Example: -- --
-- exampleWithTraceLogging :: IO () -- exampleWithTraceLogging = -- runLift -- $ withTraceLogging "my-app" local7 allLogMessages -- $ logInfo "Oh, hi there" --withTraceLogging :: Lifted IO e => Text -> Facility -> LogPredicate -> Eff (Logs : (LogWriterReader IO : e)) a -> Eff e a -- | Write LogMessages via traceM. debugTraceLogWriter :: forall h. Monad h => LogMessageRenderer Text -> LogWriter h -- | This helps to setup logging to standard ouput. module Control.Eff.LogWriter.Console -- | Enable logging to standard output using the -- consoleLogWriter. -- -- Log messages are rendered using renderLogMessageConsoleLog. -- -- Example: -- --
-- exampleWithConsoleLogWriter :: IO () -- exampleWithConsoleLogWriter = -- runLift -- $ withSomeLogging @IO -- $ withConsoleLogWriter -- $ logInfo "Oh, hi there" --withConsoleLogWriter :: (LogsTo IO e, Lifted IO e) => Eff e a -> Eff e a -- | Enable logging to standard output using the -- consoleLogWriter, with some LogMessage fields preset as -- in withIoLogging. -- -- Log messages are rendered using renderLogMessageConsoleLog. -- -- Example: -- --
-- exampleWithConsoleLogging :: IO () -- exampleWithConsoleLogging = -- runLift -- $ withConsoleLogging "my-app" local7 allLogMessages -- $ logInfo "Oh, hi there" ---- -- To vary the LogWriter use withIoLogging. withConsoleLogging :: Lifted IO e => Text -> Facility -> LogPredicate -> Eff (Logs : (LogWriterReader IO : e)) a -> Eff e a -- | Write LogMessages to standard output, formatted with -- printLogMessage. -- -- It uses stdoutLogWriter with renderLogMessageConsoleLog. consoleLogWriter :: LogWriter IO -- | A LogWriter that uses a LogMessageRenderer to render, -- and putStrLn to print it. stdoutLogWriter :: LogMessageRenderer Text -> LogWriter IO -- | This module only exposes a LogWriter for asynchronous logging; module Control.Eff.LogWriter.Async -- | Move the current LogWriter into its own thread. -- -- A bounded queue is used to forward logs to the process. -- -- If an exception is received, the logging process will be killed. -- -- Log messages are deeply evaluated before being sent to the logger -- process, to prevent that lazy evaluation leads to heavy work being -- done in the logger process instead of the caller process. -- -- Example: -- --
-- exampleAsyncLogWriter :: IO () -- exampleAsyncLogWriter = -- runLift -- $ withLogging consoleLogWriter -- $ withAsyncLogWriter (1000::Int) -- $ do logMsg "test 1" -- logMsg "test 2" -- logMsg "test 3" --withAsyncLogWriter :: (LogsTo IO e, Lifted IO e, MonadBaseControl IO (Eff e), Integral len) => len -> Eff e a -> Eff e a -- | This is a wrapper around withAsyncLogWriter and -- withIoLogging. -- -- Example: -- --
-- exampleWithAsyncLogging :: IO () -- exampleWithAsyncLogging = -- runLift -- $ withAsyncLogWriter consoleLogWriter (1000::Int) "my-app" local0 allLogMessages -- $ do logMsg "test 1" -- logMsg "test 2" -- logMsg "test 3" --withAsyncLogging :: (Lifted IO e, MonadBaseControl IO (Eff e), Integral len) => LogWriter IO -> len -> Text -> Facility -> LogPredicate -> Eff (Logs : (LogWriterReader IO : e)) a -> Eff e a -- | A coroutine based, single threaded scheduler for Processes. module Control.Eff.Concurrent.Process.SingleThreadedScheduler -- | Handle the Process effect, as well as all lower effects using -- an effect handler function. -- -- Execute the main Process and all the other processes -- spawned by it in the current thread concurrently, using a -- co-routine based, round-robin scheduler. If a process exits with eg.g -- exitNormally or exitWithError or is killed by another -- process Left ... is returned. Otherwise, the result will be -- wrapped in a Right. -- -- Every time a process _yields_ the effects are evaluated down to the a -- value of type m (Either String a). -- -- If the evaluator function runs the action down e.g. IO this -- might improve memory consumption, for long running services, with -- processes that loop endlessly. scheduleM :: forall m r a. Monad m => (forall b. Eff r b -> m b) -> m () -> Eff (InterruptableProcess r) a -> m (Either (Interrupt 'NoRecovery) a) -- | Like scheduleIO but pure. The yield effect is -- just return (). schedulePure == runIdentity . -- scheduleM (Identity . run) (return ()) schedulePure :: Eff (InterruptableProcess '[Logs, LogWriterReader PureLogWriter]) a -> Either (Interrupt 'NoRecovery) a -- | Invoke scheduleM with lift yield as yield -- effect. scheduleIO runEff == scheduleM (runLift . runEff) -- (liftIO yield) scheduleIO :: MonadIO m => (forall b. Eff r b -> Eff '[Lift m] b) -> Eff (InterruptableProcess r) a -> m (Either (Interrupt 'NoRecovery) a) -- | Invoke scheduleM with lift yield as yield -- effect. scheduleMonadIOEff == scheduleM id (liftIO -- yield) scheduleMonadIOEff :: MonadIO (Eff r) => Eff (InterruptableProcess r) a -> Eff r (Either (Interrupt 'NoRecovery) a) -- | Run processes that have the Logs and the Lift effects. -- The user must provide a log handler function. -- -- Log messages are evaluated strict. -- --
-- scheduleIOWithLogging == scheduleIO . withLogging --scheduleIOWithLogging :: HasCallStack => LogWriter IO -> Eff (InterruptableProcess LoggingAndIo) a -> IO (Either (Interrupt 'NoRecovery) a) -- | Execute a Process using scheduleM on top of Lift -- IO and withLogging String effects. defaultMainSingleThreaded :: HasCallStack => Eff (InterruptableProcess LoggingAndIo) () -> IO () instance GHC.Show.Show (Control.Eff.Concurrent.Process.SingleThreadedScheduler.OnYield r a) instance GHC.Show.Show (Control.Eff.Concurrent.Process.SingleThreadedScheduler.STS r m) instance GHC.Show.Show Control.Eff.Concurrent.Process.SingleThreadedScheduler.ProcessInfo -- | Implement Erlang style message passing concurrency. -- -- This module contains spawn which handles the Process -- effects, using TQueues and withAsync. -- -- This aims to be a pragmatic implementation, so even logging is -- supported. -- -- At the core is a main process that enters schedule and -- creates all of the internal state stored in TVars to manage -- processes with message queues. module Control.Eff.Concurrent.Process.ForkIOScheduler -- | This is the main entry point to running a message passing concurrency -- application. This function takes a Process on top of the -- SchedulerIO effect for concurrent logging. schedule :: HasCallStack => Eff InterruptableProcEff () -> Eff LoggingAndIo () -- | Start the message passing concurrency system then execute a -- Process on top of SchedulerIO effect. All logging is -- sent to standard output. defaultMain :: HasCallStack => Eff InterruptableProcEff () -> IO () -- | Start the message passing concurrency system then execute a -- Process on top of SchedulerIO effect. All logging is -- sent to standard output. defaultMainWithLogWriter :: HasCallStack => LogWriter IO -> Eff InterruptableProcEff () -> IO () -- | The concrete list of Effects of processes compatible with this -- scheduler. This builds upon SchedulerIO. type ProcEff = ConsProcess SchedulerIO -- | The concrete list of the effects, that the Process uses type InterruptableProcEff = InterruptableProcess SchedulerIO -- | The concrete list of Effects for this scheduler implementation. type SchedulerIO = (Reader SchedulerState : LoggingAndIo) -- | Type class constraint to indicate that an effect union contains the -- effects required by every process and the scheduler implementation -- itself. type HasSchedulerIO r = (HasCallStack, Lifted IO r, SchedulerIO <:: r) instance GHC.Show.Show Control.Eff.Concurrent.Process.ForkIOScheduler.ProcessInfo instance Data.Default.Class.Default Control.Eff.Concurrent.Process.ForkIOScheduler.MessageQ -- | This helps to setup logging to standard ouput. module Control.Eff.LogWriter.UDP -- | Enable logging to a (remote-) host via UDP. -- -- See exampleUdpRFC3164Logging withUDPLogWriter :: (Lifted IO e, LogsTo IO e, MonadBaseControl IO (Eff e), HasCallStack) => (LogMessage -> Text) -> String -> String -> Eff e b -> Eff e b -- | Enable logging to a remote host via UDP, with some -- LogMessage fields preset as in withIoLogging. -- -- See exampleUdpRFC3164Logging withUDPLogging :: (HasCallStack, MonadBaseControl IO (Eff e), Lifted IO e) => (LogMessage -> Text) -> String -> String -> Text -> Facility -> LogPredicate -> Eff (Logs : (LogWriterReader IO : e)) a -> Eff e a -- | This helps to setup logging to standard ouput. module Control.Eff.LogWriter.UnixSocket -- | Enable logging to a (remote-) host via UnixSocket. -- -- See exampleDevLogSyslogLogging withUnixSocketLogWriter :: (Lifted IO e, LogsTo IO e, MonadBaseControl IO (Eff e), HasCallStack) => LogMessageRenderer Text -> FilePath -> Eff e b -> Eff e b -- | Enable logging to a unix domain socket, with some -- LogMessage fields preset as in withIoLogging. -- -- See exampleDevLogSyslogLogging withUnixSocketLogging :: (HasCallStack, MonadBaseControl IO (Eff e), Lifted IO e) => LogMessageRenderer Text -> FilePath -> Text -> Facility -> LogPredicate -> Eff (Logs : (LogWriterReader IO : e)) a -> Eff e a -- | Examples for Logging. module Control.Eff.Log.Examples -- | Example code for: -- --
-- logCrash :: Interrupt -> Eff e () -- logCrash (toCrashReason -> Just reason) = logError reason -- logCrash _ = return () ---- -- Though this can be improved to: -- --
-- logCrash = traverse_ logError . toCrashReason --toCrashReason :: Interrupt x -> Maybe Text -- | Log the Interrupts logProcessExit :: forall e x. (Member Logs e, HasCallStack) => Interrupt x -> Eff e () -- | Execute a and action and return the result; if the process is -- interrupted by an error or exception, or an explicit shutdown from -- another process, or through a crash of a linked process, i.e. whenever -- the exit reason satisfies isRecoverable, return the exit -- reason. executeAndResume :: forall q r v. (SetMember Process (Process q) r, HasCallStack) => Process q (ResumeProcess v) -> Eff r (Either (Interrupt 'Recoverable) v) -- | Execute a Process action and resume the process, exit the -- process when an Interrupts was raised. Use -- executeAndResume to catch interrupts. executeAndResumeOrExit :: forall r q v. (SetMember Process (Process q) r, HasCallStack) => Process q (ResumeProcess v) -> Eff r v -- | Execute a Process action and resume the process, exit the -- process when an Interrupts was raised. Use -- executeAndResume to catch interrupts. executeAndResumeOrThrow :: forall q r v. (SetMember Process (Process q) r, HasCallStack, Member Interrupts r) => Process q (ResumeProcess v) -> Eff r v -- | Use executeAndResumeOrExit to execute YieldProcess. -- Refer to YieldProcess for more information. yieldProcess :: forall r q. (SetMember Process (Process q) r, HasCallStack, Member Interrupts r) => Eff r () -- | Send a message to a process addressed by the ProcessId. See -- SendMessage. -- -- The message will be reduced to normal form (rnf) by/in the -- caller process. sendMessage :: forall r q o. (SetMember Process (Process q) r, HasCallStack, Member Interrupts r, Typeable o, NFData o) => ProcessId -> o -> Eff r () -- | Send a Dynamic value to a process addressed by the -- ProcessId. See SendMessage. sendAnyMessage :: forall r q. (SetMember Process (Process q) r, HasCallStack, Member Interrupts r) => ProcessId -> StrictDynamic -> Eff r () -- | Exit a process addressed by the ProcessId. The process will -- exit, it might do some cleanup, but is ultimately unrecoverable. See -- SendShutdown. sendShutdown :: forall r q. (SetMember Process (Process q) r, HasCallStack, Member Interrupts r) => ProcessId -> Interrupt 'NoRecovery -> Eff r () -- | Interrupts a process addressed by the ProcessId. The process -- might exit, or it may continue. | Like sendInterrupt, but also -- return True iff the process to exit exists. sendInterrupt :: forall r q. (SetMember Process (Process q) r, HasCallStack, Member Interrupts r) => ProcessId -> Interrupt 'Recoverable -> Eff r () -- | Start a new process, the new process will execute an effect, the -- function will return immediately with a ProcessId. If the new -- process is interrupted, the process will Shutdown with the -- Interrupt wrapped in interruptToExit. For specific use -- cases it might be better to use spawnRaw. spawn :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => ProcessTitle -> Eff (InterruptableProcess q) () -> Eff r ProcessId -- | Like spawn but return (). spawn_ :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => ProcessTitle -> Eff (InterruptableProcess q) () -> Eff r () -- | Start a new process, and immediately link to it. spawnLink :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => ProcessTitle -> Eff (InterruptableProcess q) () -> Eff r ProcessId -- | Start a new process, the new process will execute an effect, the -- function will return immediately with a ProcessId. The spawned -- process has only the raw ConsProcess effects. For -- non-library code spawn might be better suited. spawnRaw :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => ProcessTitle -> Eff (ConsProcess q) () -> Eff r ProcessId -- | Like spawnRaw but return (). spawnRaw_ :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => ProcessTitle -> Eff (ConsProcess q) () -> Eff r () -- | Return True if the process is alive. isProcessAlive :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => ProcessId -> Eff r Bool -- | Return the ProcessTitle, ProcessDetails and -- ProcessState, for the given process, if the process is alive. getProcessState :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => ProcessId -> Eff r (Maybe (ProcessTitle, ProcessDetails, ProcessState)) -- | Replace the ProcessDetails of the process. updateProcessDetails :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => ProcessDetails -> Eff r () -- | Block until a message was received. See ReceiveSelectedMessage -- for more documentation. receiveAnyMessage :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => Eff r StrictDynamic -- | Block until a message was received, that is not Nothing after -- applying a callback to it. See ReceiveSelectedMessage for more -- documentation. receiveSelectedMessage :: forall r q a. (HasCallStack, Show a, SetMember Process (Process q) r, Member Interrupts r) => MessageSelector a -> Eff r a -- | Receive and cast the message to some Typeable instance. See -- ReceiveSelectedMessage for more documentation. This will wait -- for a message of the return type using receiveSelectedMessage receiveMessage :: forall a r q. (HasCallStack, Typeable a, NFData a, Show a, SetMember Process (Process q) r, Member Interrupts r) => Eff r a -- | Remove and return all messages currently enqueued in the process -- message queue. flushMessages :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => Eff r [StrictDynamic] -- | Enter a loop to receive messages and pass them to a callback, until -- the function returns Just a result. Only the messages of the -- given type will be received. If the process is interrupted by an -- exception of by a SendShutdown from another process, with an -- exit reason that satisfies isRecoverable, then the callback -- will be invoked with Left Interrupt, otherwise -- the process will be exited with the same reason using -- exitBecause. See also ReceiveSelectedMessage for more -- documentation. receiveSelectedLoop :: forall r q a endOfLoopResult. (SetMember Process (Process q) r, HasCallStack) => MessageSelector a -> (Either (Interrupt 'Recoverable) a -> Eff r (Maybe endOfLoopResult)) -> Eff r endOfLoopResult -- | Like receiveSelectedLoop but not selective. See also -- selectAnyMessage, receiveSelectedLoop. receiveAnyLoop :: forall r q endOfLoopResult. (SetMember Process (Process q) r, HasCallStack) => (Either (Interrupt 'Recoverable) StrictDynamic -> Eff r (Maybe endOfLoopResult)) -> Eff r endOfLoopResult -- | Like receiveSelectedLoop but refined to casting to a specific -- Typeable using selectMessage. receiveLoop :: forall r q a endOfLoopResult. (SetMember Process (Process q) r, HasCallStack, NFData a, Typeable a) => (Either (Interrupt 'Recoverable) a -> Eff r (Maybe endOfLoopResult)) -> Eff r endOfLoopResult -- | Returns the ProcessId of the current process. self :: (HasCallStack, SetMember Process (Process q) r) => Eff r ProcessId -- | Generate a unique Int for the current process. makeReference :: (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => Eff r Int -- | Monitor another process. When the monitored process exits a -- ProcessDown is sent to the calling process. The return value is -- a unique identifier for that monitor. There can be multiple monitors -- on the same process, and a message for each will be sent. If the -- process is already dead, the ProcessDown message will be sent -- immediately, without exit reason monitor :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => ProcessId -> Eff r MonitorReference -- | Remove a monitor created with monitor. demonitor :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => MonitorReference -> Eff r () -- | monitor another process before while performing an action and -- demonitor afterwards. withMonitor :: (HasCallStack, Member Interrupts r, SetMember Process (Process q) r, Member Interrupts r) => ProcessId -> (MonitorReference -> Eff r a) -> Eff r a -- | A MessageSelector for receiving either a monitor of the given -- process or another message. receiveWithMonitor :: (HasCallStack, Member Interrupts r, SetMember Process (Process q) r, Member Interrupts r, Typeable a, Show a) => ProcessId -> MessageSelector a -> Eff r (Either ProcessDown a) -- | Make an Interrupt for a ProcessDown message. -- -- For example: doSomething >>= either (interrupt . -- becauseProcessIsDown) return becauseProcessIsDown :: ProcessDown -> Interrupt 'Recoverable -- | A MessageSelector for the ProcessDown message of a -- specific process. selectProcessDown :: MonitorReference -> MessageSelector ProcessDown -- | Connect the calling process to another process, such that if one of -- the processes crashes (i.e. isCrash returns True), the -- other is shutdown with the Interrupt -- LinkedProcessCrashed. linkProcess :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => ProcessId -> Eff r () -- | Unlink the calling process from the other process. unlinkProcess :: forall r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => ProcessId -> Eff r () -- | Exit the process with a Interrupt. exitBecause :: forall r q a. (HasCallStack, SetMember Process (Process q) r) => Interrupt 'NoRecovery -> Eff r a -- | Exit the process. exitNormally :: forall r q a. (HasCallStack, SetMember Process (Process q) r) => Eff r a -- | Exit the process with an error. exitWithError :: forall r q a. (HasCallStack, SetMember Process (Process q) r) => String -> Eff r a fromProcessId :: Iso' ProcessId Int -- | The concrete list of Effects for this scheduler implementation. type SchedulerIO = (Reader SchedulerState : LoggingAndIo) -- | Type class constraint to indicate that an effect union contains the -- effects required by every process and the scheduler implementation -- itself. type HasSchedulerIO r = (HasCallStack, Lifted IO r, SchedulerIO <:: r) -- | The concrete list of the effects, that the Process uses type InterruptableProcEff = InterruptableProcess SchedulerIO -- | The concrete list of Effects of processes compatible with this -- scheduler. This builds upon SchedulerIO. type ProcEff = ConsProcess SchedulerIO -- | Start the message passing concurrency system then execute a -- Process on top of SchedulerIO effect. All logging is -- sent to standard output. defaultMain :: HasCallStack => Eff InterruptableProcEff () -> IO () -- | Start the message passing concurrency system then execute a -- Process on top of SchedulerIO effect. All logging is -- sent to standard output. defaultMainWithLogWriter :: HasCallStack => LogWriter IO -> Eff InterruptableProcEff () -> IO () -- | This is the main entry point to running a message passing concurrency -- application. This function takes a Process on top of the -- SchedulerIO effect for concurrent logging. schedule :: HasCallStack => Eff InterruptableProcEff () -> Eff LoggingAndIo () -- | Like scheduleIO but pure. The yield effect is -- just return (). schedulePure == runIdentity . -- scheduleM (Identity . run) (return ()) schedulePure :: Eff (InterruptableProcess '[Logs, LogWriterReader PureLogWriter]) a -> Either (Interrupt 'NoRecovery) a -- | Execute a Process using scheduleM on top of Lift -- IO and withLogging String effects. defaultMainSingleThreaded :: HasCallStack => Eff (InterruptableProcess LoggingAndIo) () -> IO () -- | A value to be sent when timer started with startTimer has -- elapsed. data TimerElapsed -- | The reference to a timer started by startTimer, required to -- stop a timer via cancelTimer. data TimerReference -- | A number of micro seconds. data Timeout -- | Wait for a message of the given type for the given time. When no -- message arrives in time, return Nothing. This is based on -- receiveSelectedAfter. receiveAfter :: forall a r q. (Lifted IO q, HasCallStack, SetMember Process (Process q) r, Member Interrupts r, Typeable a, NFData a, Show a) => Timeout -> Eff r (Maybe a) -- | Wait for a message of the given type for the given time. When no -- message arrives in time, return Left TimerElapsed. This -- is based on selectTimerElapsed and startTimer. receiveSelectedAfter :: forall a r q. (Lifted IO q, HasCallStack, SetMember Process (Process q) r, Member Interrupts r, Show a) => MessageSelector a -> Timeout -> Eff r (Either TimerElapsed a) -- | Like receiveWithMonitor combined with -- receiveSelectedAfter. receiveSelectedWithMonitorAfter :: forall a r q. (Lifted IO q, HasCallStack, SetMember Process (Process q) r, Member Interrupts r, Show a) => ProcessId -> MessageSelector a -> Timeout -> Eff r (Either (Either ProcessDown TimerElapsed) a) -- | A MessageSelector matching TimerElapsed messages created -- by startTimer. selectTimerElapsed :: TimerReference -> MessageSelector TimerElapsed -- | Send a message to a given process after waiting. The message is -- created by applying the function parameter to the -- TimerReference, such that the message can directly refer to the -- timer. sendAfter :: forall r q message. (Lifted IO q, HasCallStack, SetMember Process (Process q) r, Member Interrupts r, Typeable message, NFData message) => ProcessId -> Timeout -> (TimerReference -> message) -> Eff r TimerReference -- | Start a new timer, after the time has elapsed, TimerElapsed is -- sent to calling process. The message also contains the -- TimerReference returned by this function. Use -- cancelTimer to cancel the timer. Use selectTimerElapsed -- to receive the message using receiveSelectedMessage. To receive -- messages with guarded with a timeout see receiveAfter. startTimer :: forall r q. (Lifted IO q, HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => Timeout -> Eff r TimerReference -- | Cancel a timer started with startTimer. cancelTimer :: forall r q. (Lifted IO q, HasCallStack, SetMember Process (Process q) r, Member Interrupts r) => TimerReference -> Eff r () -- | This is a tag-type that wraps around a ProcessId and holds an -- Pdu index type. newtype Endpoint protocol Endpoint :: ProcessId -> Endpoint protocol [_fromEndpoint] :: Endpoint protocol -> ProcessId -- | This type function takes an Pdu and analysis the reply type, -- i.e. the Synchronicity and evaluates to either t for -- an Pdu x (Synchronous t) or to '()' for an Pdu x -- Asynchronous. type family ProtocolReply (s :: Synchronicity) -- | The (promoted) constructors of this type specify (at the type level) -- the reply behavior of a specific constructor of an Pdu -- instance. data Synchronicity -- | Specify that handling a request is a blocking operation with a -- specific return type, e.g. ('Synchronous (Either RentalError -- RentalId)) Synchronous :: Type -> Synchronicity -- | Non-blocking, asynchronous, request handling Asynchronous :: Synchronicity -- | A Constraint that bundles the requirements for the Pdu -- values of a protocol. -- -- This ensures that Pdus can be strictly and deeply evaluated and -- shown such that for example logging is possible. type TangiblePdu p r = (Typeable p, Typeable r, Tangible (Pdu p r)) -- | A set of constraints for types that can evaluated via NFData, -- compared via Ord and presented dynamically via Typeable, -- and represented both as values via Show. type Tangible i = (NFData i, Typeable i, Show i) -- | This data family defines the **protocol data units**(PDU) of a -- protocol. -- -- A Protocol in the sense of a communication interface description -- between processes. -- -- The first parameter is usually a user defined type that identifies the -- protocol that uses the Pdus are. It maybe a phantom -- type. -- -- The second parameter specifies if a specific constructor of an -- (GADT-like) Pdu instance is Synchronous, i.e. returns -- a result and blocks the caller or if it is Asynchronous -- -- Example: -- --
-- data BookShop deriving Typeable
--
-- data instance Pdu BookShop r where
-- RentBook :: BookId -> Pdu BookShop ('Synchronous (Either RentalError RentalId))
-- BringBack :: RentalId -> Pdu BookShop 'Asynchronous
--
-- type BookId = Int
-- type RentalId = Int
-- type RentalError = String
--
data family Pdu (protocol :: Type) (reply :: Synchronicity)
-- | A class for Pdu instances that embed other Pdu. A
-- Prism for the embedded Pdu is the center of this class
--
-- Laws: embeddedPdu = prism' embedPdu fromPdu
class EmbedProtocol protocol embeddedProtocol
-- | A Prism for the embedded Pdus.
embeddedPdu :: EmbedProtocol protocol embeddedProtocol => Prism' (Pdu protocol result) (Pdu embeddedProtocol result)
-- | Embed the Pdu value of an embedded protocol into the
-- corresponding Pdu value.
embedPdu :: EmbedProtocol protocol embeddedProtocol => Pdu embeddedProtocol r -> Pdu protocol r
-- | Examine a Pdu value from the outer protocol, and return it, if
-- it embeds a Pdu of embedded protocol, otherwise return
-- Nothing/
fromPdu :: EmbedProtocol protocol embeddedProtocol => Pdu protocol r -> Maybe (Pdu embeddedProtocol r)
fromEndpoint :: forall protocol_aRHy protocol_aRV4. Iso (Endpoint protocol_aRHy) (Endpoint protocol_aRV4) ProcessId ProcessId
-- | Tag a ProcessId with an Pdu type index to mark it a
-- Endpoint process handling that API
proxyAsEndpoint :: proxy protocol -> ProcessId -> Endpoint protocol
-- | Tag a ProcessId with an Pdu type index to mark it a
-- Endpoint process handling that API
asEndpoint :: forall protocol. ProcessId -> Endpoint protocol
-- | The reader effect for ProcessIds for Pdus, see
-- runEndpointReader
type EndpointReader o = Reader (Endpoint o)
-- | Instead of passing around a Endpoint value and passing to
-- functions like cast or call, a Endpoint can
-- provided by a Reader effect, if there is only a single
-- server for a given Pdu instance. This type alias is
-- convenience to express that an effect has Process and a reader
-- for a Endpoint.
type ServesProtocol o r q = (Typeable o, SetMember Process (Process q) r, Member (EndpointReader o) r)
-- | Send a request Pdu that has no reply and return immediately.
--
-- The type signature enforces that the corresponding Pdu clause
-- is Asynchronous. The operation never fails, if it is important
-- to know if the message was delivered, use call instead.
--
-- The message will be reduced to normal form (rnf) in the
-- caller process.
cast :: forall o' o r q. (HasCallStack, SetMember Process (Process q) r, Member Interrupts r, TangiblePdu o' 'Asynchronous, TangiblePdu o 'Asynchronous, EmbedProtocol o' o) => Endpoint o' -> Pdu o 'Asynchronous -> Eff r ()
-- | Send a request Pdu and wait for the server to return a result
-- value.
--
-- The type signature enforces that the corresponding Pdu clause
-- is Synchronous.
--
-- Always prefer callWithTimeout over call
call :: forall result protocol' protocol r q. (SetMember Process (Process q) r, Member Interrupts r, TangiblePdu protocol' ( 'Synchronous result), TangiblePdu protocol ( 'Synchronous result), EmbedProtocol protocol' protocol, Tangible result, HasCallStack) => Endpoint protocol' -> Pdu protocol ( 'Synchronous result) -> Eff r result
-- | Send an request Pdu and wait for the server to return a result
-- value.
--
-- The type signature enforces that the corresponding Pdu clause
-- is Synchronous.
--
-- If the server that was called dies, this function interrupts the
-- process with ProcessDown. If the server takes longer to reply
-- than the given timeout, this function interrupts the process with
-- TimeoutInterrupt.
--
-- Always prefer this function over call
callWithTimeout :: forall result protocol' protocol r q. (SetMember Process (Process q) r, Member Interrupts r, TangiblePdu protocol' ( 'Synchronous result), TangiblePdu protocol ( 'Synchronous result), EmbedProtocol protocol' protocol, Tangible result, Member Logs r, Lifted IO q, Lifted IO r, HasCallStack) => Endpoint protocol' -> Pdu protocol ( 'Synchronous result) -> Timeout -> Eff r result
-- | Run a reader effect that contains the one server handling a
-- specific Pdu instance.
runEndpointReader :: HasCallStack => Endpoint o -> Eff (EndpointReader o : r) a -> Eff r a
-- | Get the Endpoint registered with runEndpointReader.
askEndpoint :: Member (EndpointReader o) e => Eff e (Endpoint o)
-- | Like call but take the Endpoint from the reader provided
-- by runEndpointReader.
callEndpointReader :: forall reply o r q. (ServesProtocol o r q, HasCallStack, Tangible reply, TangiblePdu o ( 'Synchronous reply), Member Interrupts r) => Pdu o ( 'Synchronous reply) -> Eff r reply
-- | Like cast but take the Endpoint from the reader provided
-- by runEndpointReader.
castEndpointReader :: forall o r q. (ServesProtocol o r q, HasCallStack, Member Interrupts r, TangiblePdu o 'Asynchronous) => Pdu o 'Asynchronous -> Eff r ()
-- | This data family defines the **protocol data units**(PDU) of a
-- protocol.
--
-- A Protocol in the sense of a communication interface description
-- between processes.
--
-- The first parameter is usually a user defined type that identifies the
-- protocol that uses the Pdus are. It maybe a phantom
-- type.
--
-- The second parameter specifies if a specific constructor of an
-- (GADT-like) Pdu instance is Synchronous, i.e. returns
-- a result and blocks the caller or if it is Asynchronous
--
-- Example:
--
--
-- data BookShop deriving Typeable
--
-- data instance Pdu BookShop r where
-- RentBook :: BookId -> Pdu BookShop ('Synchronous (Either RentalError RentalId))
-- BringBack :: RentalId -> Pdu BookShop 'Asynchronous
--
-- type BookId = Int
-- type RentalId = Int
-- type RentalError = String
--
data family Pdu (protocol :: Type) (reply :: Synchronicity)
-- | Alias for the effect that contains the observers managed by
-- manageObservers
type ObserverState o = State (Observers o)
-- | Internal state for manageObservers
data Observers o
-- | A protocol for managing Observers, encompassing registration
-- and de-registration of Observers.
data ObserverRegistry o
-- | Describes a process that observes another via Asynchronous
-- Pdu messages.
--
-- An observer consists of a filter and a process id. The filter converts
-- an observation to a message understood by the observer process, and
-- the ProcessId is used to send the message.
data Observer o
[Observer] :: (Tangible o, TangiblePdu p 'Asynchronous, Tangible (Endpoint p), Typeable p) => (o -> Maybe (Pdu p 'Asynchronous)) -> Endpoint p -> Observer o
-- | And an Observer to the set of recipients for all observations
-- reported by observed. Note that the observers are keyed by the
-- observing process, i.e. a previous entry for the process contained in
-- the Observer is overwritten. If you want multiple entries for a
-- single process, just combine several filter functions.
registerObserver :: (SetMember Process (Process q) r, HasCallStack, Member Interrupts r, TangibleObserver o, EmbedProtocol x (ObserverRegistry o), TangiblePdu x 'Asynchronous) => Observer o -> Endpoint x -> Eff r ()
-- | Send the ForgetObserver message
forgetObserver :: (SetMember Process (Process q) r, HasCallStack, Member Interrupts r, Typeable o, NFData o, EmbedProtocol x (ObserverRegistry o), TangiblePdu x 'Asynchronous) => Observer o -> Endpoint x -> Eff r ()
-- | Based on the Pdu instance for Observer this simplified
-- writing a callback handler for observations. In order to register to
-- and ObserverRegistry use toObserver.
handleObservations :: (HasCallStack, Typeable o, SetMember Process (Process q) r, NFData (Observer o)) => (o -> Eff r ()) -> Pdu (Observer o) 'Asynchronous -> Eff r ()
-- | Use a Endpoint as an Observer for
-- handleObservations.
toObserver :: TangibleObserver o => Endpoint (Observer o) -> Observer o
-- | Create an Observer that conditionally accepts all observations
-- of the given type and applies the given function to them; the function
-- takes an observation and returns an Pdu cast that the observer
-- server is compatible to.
toObserverFor :: (TangibleObserver o, Typeable a, TangiblePdu a 'Asynchronous) => (o -> Pdu a 'Asynchronous) -> Endpoint a -> Observer o
-- | Provide the implementation for the ObserverRegistry Protocol,
-- this handled RegisterObserver and ForgetObserver
-- messages. It also adds the ObserverState constraint to the
-- effect list.
handleObserverRegistration :: forall o q r. (HasCallStack, Typeable o, SetMember Process (Process q) r, Member (ObserverState o) r, Member Logs r) => Pdu (ObserverRegistry o) 'Asynchronous -> Eff r ()
-- | Keep track of registered Observers.
--
-- Handle the ObserverState introduced by
-- handleObserverRegistration.
manageObservers :: Eff (ObserverState o : r) a -> Eff r a
-- | The empty ObserverState
emptyObservers :: Observers o
-- | Report an observation to all observers. The process needs to
-- manageObservers and to handleObserverRegistration.
observed :: forall o r q. (SetMember Process (Process q) r, Member (ObserverState o) r, Member Interrupts r, TangibleObserver o) => o -> Eff r ()
-- | A Reader for an ObservationQueue.
type ObservationQueueReader a = Reader (ObservationQueue a)
-- | Contains a TBQueue capturing observations. See
-- spawnLinkObservationQueueWriter, readObservationQueue.
data ObservationQueue a
-- | Read queued observations captured and enqueued in the shared
-- TBQueue by spawnLinkObservationQueueWriter. This blocks
-- until something was captured or an interrupt or exceptions was thrown.
-- For a non-blocking variant use tryReadObservationQueue or
-- flushObservationQueue.
readObservationQueue :: forall o r. (Member (ObservationQueueReader o) r, HasCallStack, MonadIO (Eff r), Typeable o, Member Logs r) => Eff r o
-- | Read queued observations captured and enqueued in the shared
-- TBQueue by spawnLinkObservationQueueWriter. Return the
-- oldest enqueued observation immediately or Nothing if the queue
-- is empty. Use readObservationQueue to block until an
-- observation is observed.
tryReadObservationQueue :: forall o r. (Member (ObservationQueueReader o) r, HasCallStack, MonadIO (Eff r), Typeable o, Member Logs r) => Eff r (Maybe o)
-- | Read at once all currently queued observations captured and enqueued
-- in the shared TBQueue by
-- spawnLinkObservationQueueWriter. This returns immediately all
-- currently enqueued observations. For a blocking variant use
-- readObservationQueue.
flushObservationQueue :: forall o r. (Member (ObservationQueueReader o) r, HasCallStack, MonadIO (Eff r), Typeable o, Member Logs r) => Eff r [o]
-- | Create a mutable queue for observations. Use
-- spawnLinkObservationQueueWriter for a simple way to get a
-- process that enqueues all observations.
--
-- -- withObservationQueue 100 $ do -- q <- ask @(ObservationQueueReader TestEvent) -- wq <- spawnLinkObservationQueueWriter q -- registerObserver wq testServer -- ... -- cast testServer DoSomething -- evt <- readObservationQueue @TestEvent -- ... --withObservationQueue :: forall o b e len. (HasCallStack, Typeable o, Show o, Member Logs e, Lifted IO e, Integral len, Member Interrupts e) => len -> Eff (ObservationQueueReader o : e) b -> Eff e b -- | Spawn a process that can be used as an Observer that enqueues -- the observations into an ObservationQueue. See -- withObservationQueue for an example. -- -- The observations can be obtained by readObservationQueue. All -- observations are captured up to the queue size limit, such that the -- first message received will be first message returned by -- readObservationQueue. spawnLinkObservationQueueWriter :: forall o q h. (TangibleObserver o, TangiblePdu (Observer o) 'Asynchronous, Member Logs q, Lifted IO q, LogsTo h (InterruptableProcess q), HasCallStack) => ObservationQueue o -> Eff (InterruptableProcess q) (Observer o)