-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Daemons in Haskell made fun and easy -- -- Control.Pipe.C3 provides simple RPC-like wrappers for pipes. -- -- Control.Pipe.Serialize provides serialization and incremental -- deserialization pipes. -- -- Control.Pipe.Socket provides functions to setup pipes around -- sockets. -- -- System.Daemon provides a high-level interface to starting -- daemonized programs that are controlled through sockets. -- -- System.Posix.Daemon provides a low-level interface to starting, -- and controlling detached jobs. -- -- See the README.md file and the homepage for details. @package daemons @version 0.3.0 -- | This module provides the deserializer and serializer -- pipes to convert ByteStrings off of pipes into typed values. -- -- In order to use it, the types of the values need to have -- Serialize instances. These can be derived automatically using -- Ghc.Generics: -- --
-- {-# LANGUAGE DeriveGeneric #-}
--
-- data Foo = Bar String | Baz Int
-- deriving ( Generic )
--
-- instance Serialize Foo
--
--
-- Note that in the above example: we use the DeriveGeneric
-- extension, derive a Generic instance for our data-type, and
-- write an empty Serialize instance.
module Control.Pipe.Serialize
-- | Serialize data into strict ByteStrings.
serializer :: (Serialize a, Monad m) => Pipe a ByteString m ()
-- | De-serialize data from strict ByteStrings. Uses
-- cereal's incremental Get parser.
deserializer :: (Serialize a, Monad m, MonadFail m) => Pipe ByteString a m ()
module Control.Pipe.Socket
-- | Stream data from the socket.
socketReader :: MonadIO m => Socket -> Producer ByteString m ()
-- | Stream data to the socket.
socketWriter :: MonadIO m => Socket -> Consumer ByteString m ()
-- | A simple handler: takes an incoming stream of ByteStrings, an
-- stream of ByteStrings, and ties them together somehow.
-- Conceptually, the simplest handler would be identity:
--
-- -- import Control.Monad -- import Control.Pipe -- import Data.ByteString.Char8 -- -- handler reader writer = do -- let identity = forever $ do -- x <- await -- yield x -- runPipe (writer <+< identity <+< reader) ---- -- See the pipes tutorial for more examples of writing pipes. -- -- Since ByteStrings are fairly boring by themseleves, have a look -- at Control.Pipe.Serialize which lets you deserialize/serialize -- pipes of ByteStrings easily. type Handler r = Producer ByteString IO () -> Consumer ByteString IO () -> IO r -- | Listen for connections on the given socket, and run Handler on -- each received connection. The socket should previously have been bound -- to a port or to a file. Each handler is run in its own thread. Even in -- case of an error, the handlers' sockets are closed. runSocketServer :: MonadIO m => Socket -> Handler () -> m () -- | Run Handler on the given socket. runSocketClient :: MonadIO m => Socket -> Handler r -> m r module Control.Pipe.C3 -- | Send a single command over the outgoing pipe and wait for a response. -- If the incoming pipe is closed before a response arrives, returns -- Nothing. commandSender :: (Serialize a, Serialize b) => a -> Handler (Maybe b) -- | Wait for commands on the incoming pipe, handle them, and send the -- reponses over the outgoing pipe. commandReceiver :: (Serialize a, Serialize b) => (a -> IO b) -> Handler () -- | This module provides a simple interface to creating, checking the -- status of, and stopping background jobs. -- -- Use runDetached to start a background job. For instance, here -- is a daemon that peridically hits a webserver: -- --
-- import Control.Concurrent
-- import Control.Monad
-- import Data.Default
-- import Data.Maybe
-- import Network.BSD
-- import Network.HTTP
-- import Network.URI
-- import System.Posix.Daemon
--
-- main :: IO ()
-- main = runDetached (Just "diydns.pid") def $ forever $ do
-- hostname <- getHostName
-- _ <- simpleHTTP
-- (Request { rqURI = fromJust (parseURI "http://foo.com/dns")
-- , rqMethod = GET
-- , rqHeaders = []
-- , rqBody = hostname })
-- threadDelay (600 * 1000 * 1000)
--
--
-- To check if the above job is running, use isRunning with the
-- same pidfile:
--
-- -- isRunning "diydns.pid" ---- -- Finally, to stop the above job (maybe because we're rolling a new -- version of it), use kill: -- --
-- kill "diydns.pid" ---- -- To stop a job and wait for it to close (and release its pidfile), use -- killAndWait: -- --
-- killAndWait "diydns.pid" >> doSomething ---- -- As a side note, the code above is a script that the author uses as a -- sort of homebrew dynamic DNS: the remote address is a CGI script that -- records the IP addresses of all incoming requests in separate files -- named after the contents of the requests; the addresses are then -- viewable with any browser. module System.Posix.Daemon -- | Run the given action detached from the current terminal; this creates -- an entirely new process. This function returns immediately. Uses the -- double-fork technique to create a well behaved daemon. If -- pidfile is given, check/write it; if we cannot obtain a lock -- on the file, another process is already using it, so fail. The -- redirection parameter controls what to do with the standard -- channels (stdin, stderr, and stdout). -- -- See: http://www.enderunix.org/docs/eng/daemon.php -- -- Note: All unnecessary fds should be close before calling this. -- Otherwise, you get an fd leak. runDetached :: Maybe FilePath -> Redirection -> IO () -> IO () -- | Where should the output (and input) of a daemon be redirected to? (we -- can't just leave it to the current terminal, because it may be closed, -- and that would kill the daemon). -- -- When in doubt, just use def, the default value. -- -- DevNull causes the output to be redirected to -- /dev/null. This is safe and is what you want in most cases. -- -- If you don't want to lose the output (maybe because you're using it -- for logging), use ToFile, instead. data Redirection DevNull :: Redirection ToFile :: FilePath -> Redirection -- | Return True if the given file is locked by a process. In our -- case, returns True when the daemon that created the file is -- still alive. isRunning :: FilePath -> IO Bool -- | Send sigQUIT to the process recorded in the pidfile. This gives -- the process a chance to close cleanly. kill :: FilePath -> IO () -- | Kill a process and wait for it to release its pidfile killAndWait :: FilePath -> IO () -- | Send sigKILL to the process recorded in the pidfile. This -- immediately kills the process. brutalKill :: FilePath -> IO () instance GHC.Show.Show System.Posix.Daemon.Redirection instance Data.Default.Class.Default System.Posix.Daemon.Redirection -- | An RPC-like interface for daemons is provided by -- ensureDaemonRunning and runClient. -- -- A more versatile interface that lets you supply your own -- Handler is provided by ensureDaemonWithHandlerRunning -- and runClientWithHandler. These are useful if, for instance, -- you need streaming requests or replies, or if you need to change your -- event handler at runtime. -- -- The event handling loop is provided by runInForeground. You may -- want to use this for debugging purposes or if you want to handle -- daemonization manually. module System.Daemon -- | Simple wrapper around ensureDaemonWithHandlerRunning which uses -- a simple function to respond to commands and doesn't deal with pipes. -- -- The handler is just a function that takes a command and -- returns a response. ensureDaemonRunning :: (Serialize a, Serialize b) => String -> DaemonOptions -> (a -> IO b) -> IO () -- | Start a daemon running on the given port, using the given handler to -- respond to events. If the daemon is already running, don't do -- anything. Returns immediately. -- -- The pidfile PidFile options will be created and locked. This -- function checks the pidfile to see if the daemon is already running. -- -- The daemon will listen for incoming connections on all interfaces on -- daemonPort options. -- -- The handler is a function that takes the reader and writer -- ByteString pipes and does something with them. See -- commandReceiver for an example handler. ensureDaemonWithHandlerRunning :: String -> DaemonOptions -> Handler () -> IO () -- | Send a command to the daemon running at the given network address and -- wait for a response. -- -- This is a simple wrapper around runClientWithHandler that sends -- a single command and waits for a single response. -- -- If the connection is closed before receiving a response, return -- Nothing. runClient :: (Serialize a, Serialize b) => HostName -> Port -> a -> IO (Maybe b) -- | Connect to the given network address and run the handler on the reader -- and wrier pipes for the socket. -- -- The handler is a function that takes the reader and writer -- ByteString pipes and does something with them. For an example -- handler, see commandSender, which sends a command and waits for -- a response. runClientWithHandler :: HostName -> Port -> Handler a -> IO a -- | The configuration options of a daemon. See ensureDaemonRunning -- for a description of each. data DaemonOptions DaemonOptions :: Port -> PidFile -> Bool -> DaemonOptions [daemonPort] :: DaemonOptions -> Port [daemonPidFile] :: DaemonOptions -> PidFile [printOnDaemonStarted] :: DaemonOptions -> Bool -- | The location of the daemon's pidfile. data PidFile InHome :: PidFile PidFile :: FilePath -> PidFile type HostName = String type Port = Int -- | Start the given handler in the foreground. It will listen and respond -- to events on the given port. -- -- This is the function that ensureDaemonWithHandlerRunning runs -- on the daemon thread. runInForeground :: Port -> Handler () -> IO () -- | Create a socket and bind it to the given port. bindPort :: Port -> IO Socket -- | Create a socket connected to the given network address. getSocket :: HostName -> Port -> IO Socket instance GHC.Show.Show System.Daemon.DaemonOptions instance GHC.Show.Show System.Daemon.PidFile instance Data.Default.Class.Default System.Daemon.DaemonOptions instance Data.String.IsString System.Daemon.PidFile