-- 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.2.0 -- | 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 Show Redirection instance Default Redirection 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 -- | 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) => Pipe ByteString a m ()
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 ()
-- | 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 Show PidFile
instance Show DaemonOptions
instance IsString PidFile
instance Default DaemonOptions