systemd-socket-activation 1.0.0.1 → 1.0.0.2
raw patch · 12 files changed
+163/−140 lines, 12 filesdep ~basedep ~containersdep ~networkPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: base, containers, network, text
API changes (from Hackage documentation)
Files
- changelog.md +11/−0
- readme.md +8/−0
- src/SocketActivation.hs +15/−18
- src/SocketActivation/CheckRecipient.hs +12/−11
- src/SocketActivation/Concepts.hs +29/−21
- src/SocketActivation/Env.hs +21/−16
- src/SocketActivation/GetByName.hs +16/−16
- src/SocketActivation/GetFileDescriptors.hs +12/−12
- src/SocketActivation/GetSockets.hs +10/−10
- src/SocketActivation/IO.hs +8/−8
- src/SocketActivation/Parsing.hs +10/−11
- systemd-socket-activation.cabal +11/−17
+ changelog.md view
@@ -0,0 +1,11 @@+# 1.0.0.2 (2023-01-08)++Support GHC 9.4++# 1.0.0.1 (2021-12-27)++Support GHC 9.2++# 1 (2021-07-07)++Initial release
+ readme.md view
@@ -0,0 +1,8 @@+"Socket activation" is the a feature of systemd. ([documentation])++We use it for web servers, to avoid the momentary downtime that otherwise occurs+while restarting processes. Because the socket is manged by systemd, not by our+process, the socket remains even while our process is down. Requests to the+socket are queued until our process comes back up to respond.++ [documentation]: https://www.freedesktop.org/software/systemd/man/sd_listen_fds_with_names.html
src/SocketActivation.hs view
@@ -1,29 +1,26 @@ module SocketActivation (- -- * Actions- getMySocketByName-- -- * Types- , Name (..), VarName (..), Socket, Error (..)-- ) where+ {- * Actions -} getMySocketByName,+ {- * Types -} Name (..), VarName (..), Socket, Error (..),+ )+ where -import Control.Applicative (Applicative ((*>)))-import Control.Monad (Monad (return, (>>=)))-import Data.Either (Either, either)-import System.IO (IO, print)+import Control.Applicative (Applicative ((*>)))+import Control.Monad (Monad (return, (>>=)))+import Data.Either (Either, either)+import System.IO (IO, print) -import qualified Control.Exception as Ex+import qualified Control.Exception as Ex import qualified SocketActivation.CheckRecipient as SA-import qualified SocketActivation.Concepts as SA-import qualified SocketActivation.Env as SA-import qualified SocketActivation.GetByName as SA+import qualified SocketActivation.Env as SA+import qualified SocketActivation.GetByName as SA -import SocketActivation.Concepts as Concepts+import SocketActivation.Concepts+ (Socket, Error (..), VarName (..), Name (..)) -getMySocketByName :: SA.Name -> IO SA.Socket+getMySocketByName :: Name -> IO Socket getMySocketByName name = f SA.checkRecipient *> f (SA.getSocketByName name) where- f :: IO (Either SA.Error a) -> IO a+ f :: IO (Either Error a) -> IO a f = (>>= either (\e -> (SA.getEnvVars >>= print) *> Ex.throw e) return)
src/SocketActivation/CheckRecipient.hs view
@@ -2,18 +2,18 @@ module SocketActivation.CheckRecipient where -import Control.Monad (Monad (return, (>>=)))-import Control.Monad.IO.Class (MonadIO (liftIO))-import Data.Either (Either)-import Data.Eq (Eq ((==)))-import Data.Function ((.))-import System.IO (IO)+import Control.Monad (Monad (return, (>>=)))+import Control.Monad.IO.Class (MonadIO (liftIO))+import Data.Either (Either)+import Data.Eq (Eq ((==)))+import Data.Function ((.))+import System.IO (IO) -import qualified System.Posix.Process as Sys+import qualified System.Posix.Process as Sys -import SocketActivation.Concepts-import SocketActivation.Env-import SocketActivation.IO+import SocketActivation.Concepts (Error(WrongProcess), Recipient (recipientPID))+import SocketActivation.Env (getEnv')+import SocketActivation.IO (IO' (IO', run), throwError) checkRecipient :: IO (Either Error ()) checkRecipient = run (getIt >>= checkIt)@@ -25,4 +25,5 @@ checkRecipient' x = run (getMyPid >>= throwIfDifferent) where getMyPid = liftIO Sys.getProcessID- throwIfDifferent y = if recipientPID x == y then return () else throwError WrongProcess+ throwIfDifferent y =+ if recipientPID x == y then return () else throwError WrongProcess
src/SocketActivation/Concepts.hs view
@@ -1,38 +1,46 @@ module SocketActivation.Concepts- ( Recipient (..)- , ProcessID- , Count (..)- , Name (..)- , Names (..)- , VarName (..)- , Fd (..)- , Socket- , Error (..)- ) where+ (+ Recipient (..),+ ProcessID,+ Count (..),+ Name (..),+ Names (..),+ VarName (..),+ Fd (..),+ Socket,+ Error (..),+ )+ where -import Control.Exception (Exception)-import Data.String (IsString)-import Data.Text (Text)-import Numeric.Natural (Natural)-import Prelude (Bounded, Enum, Eq, Ord, Show)+import Control.Exception (Exception)+import Data.String (IsString)+import Data.Text (Text)+import Numeric.Natural (Natural)+import Prelude (Bounded, Enum, Eq, Ord, Show) -import Network.Socket (Socket)-import System.Posix.Types (Fd (..), ProcessID)+import Network.Socket (Socket)+import System.Posix.Types (Fd (..), ProcessID) --- | The ID of the process to whom systemd has given the sockets. A process should not use sockets that are intended for someone else, so we should always check that this matches our own PID before proceeding doing anything with the sockets.+{-| The ID of the process to whom systemd has given the sockets++A process should not use sockets that are intended for someone else, so we+should always check that this matches our own PID before proceeding doing+anything with the sockets. -} newtype Recipient = RecipientPID { recipientPID :: ProcessID } deriving stock (Eq, Show) --- | The number of sockets that systemd has given the process.+{-| The number of sockets that systemd has given the process -} newtype Count = CountNat { countNat :: Natural } deriving stock (Eq, Show) --- | The name of a socket, corresponding to the socket's FileDescriptorName in the systemd config.+{-| The name of a socket, corresponding to the socket's FileDescriptorName in+ the systemd config -} newtype Name = NameText { nameText :: Text } deriving stock (Eq, Ord, Show) deriving newtype IsString --- | The names of the sockets that we have been given, corresponding to the FileDescriptorName of each systemd socket.+{-| The names of the sockets that we have been given, corresponding to the+ FileDescriptorName of each systemd socket -} newtype Names = NamesList { namesList :: [Name] } deriving stock (Eq, Show)
src/SocketActivation/Env.hs view
@@ -1,22 +1,23 @@ module SocketActivation.Env where -import Control.Monad (Monad (return, (>>=)))-import Control.Monad.IO.Class (MonadIO (liftIO))-import Data.Either (Either, either)-import Data.Function (($), (.))-import Data.Maybe (Maybe (..), maybe)-import Data.Text (Text)-import Data.Traversable (Traversable (traverse))-import Prelude (Bounded (maxBound, minBound))-import System.IO (IO)-import Text.Show (show)+import Control.Monad (Monad (return, (>>=)))+import Control.Monad.IO.Class (MonadIO (liftIO))+import Data.Either (Either, either)+import Data.Function (($), (.))+import Data.Maybe (Maybe (..), maybe)+import Data.Text (Text)+import Data.Traversable (Traversable (traverse))+import Prelude (Bounded (maxBound, minBound))+import System.IO (IO)+import Text.Show (show) -import qualified Data.Text as Text-import qualified System.Environment as Sys+import qualified Data.Text as Text+import qualified System.Environment as Sys -import SocketActivation.Concepts-import SocketActivation.IO-import SocketActivation.Parsing+import SocketActivation.Concepts+ (Error (Invalid, Missing), VarName (..), Names, Count, Recipient)+import SocketActivation.IO (IO' (IO', run), throwError)+import SocketActivation.Parsing (readRecipient, readCount, readNames) getVarText :: VarName -> IO (Either Error Text) getVarText name = run (getMaybe >>= throwIfMissing >>= pack)@@ -26,7 +27,11 @@ pack = return . Text.pack getEnvVars :: IO [(VarName, Maybe Text)]-getEnvVars = traverse (\x -> getVarText x >>= \y -> return (x, either (\_ -> Nothing) Just y)) [minBound .. maxBound]+getEnvVars =+ traverse+ (\x -> getVarText x >>= \y ->+ return (x, either (\_ -> Nothing) Just y))+ [minBound .. maxBound] data Env a = Env VarName (Text -> Maybe a)
src/SocketActivation/GetByName.hs view
@@ -1,23 +1,23 @@ module SocketActivation.GetByName where -import Control.Applicative (Applicative ((<*>)),- (<$>))-import Control.Monad (Monad (return, (>>=)))-import Control.Monad.IO.Class (MonadIO (liftIO))-import Data.Either (Either)-import Data.Function ((.))-import Data.List (zip)-import Data.Map (Map)-import Data.Maybe (maybe)-import System.IO (IO)+import Control.Applicative (Applicative ((<*>)), (<$>))+import Control.Monad (Monad (return, (>>=)))+import Control.Monad.IO.Class (MonadIO (liftIO))+import Data.Either (Either)+import Data.Function ((.))+import Data.List (zip)+import Data.Map (Map)+import Data.Maybe (maybe)+import System.IO (IO) -import qualified Data.Map as Map+import qualified Data.Map as Map -import SocketActivation.Concepts-import SocketActivation.Env-import SocketActivation.GetFileDescriptors-import SocketActivation.GetSockets-import SocketActivation.IO+import SocketActivation.Concepts+ (Socket, Fd, Error (NoSuchName), Names (namesList), Name)+import SocketActivation.Env (getEnv')+import SocketActivation.GetFileDescriptors (getFileDescriptorList)+import SocketActivation.GetSockets (getSocketList, fdSocket)+import SocketActivation.IO (IO' (IO', run), throwError) getNameList :: IO (Either Error [Name]) getNameList = run (getNames >>= unwrap)
src/SocketActivation/GetFileDescriptors.hs view
@@ -1,19 +1,19 @@ module SocketActivation.GetFileDescriptors where -import Control.Monad (Monad (return, (>>=)))-import Data.Either (Either)-import Data.Function ((.))-import Data.Int (Int)-import Data.List (take)-import Numeric.Natural (Natural)-import Prelude (fromIntegral)-import System.IO (IO)+import Control.Monad (Monad (return, (>>=)))+import Data.Either (Either)+import Data.Function ((.))+import Data.Int (Int)+import Data.List (take)+import Numeric.Natural (Natural)+import Prelude (fromIntegral)+import System.IO (IO) -import SocketActivation.Concepts-import SocketActivation.Env-import SocketActivation.IO+import SocketActivation.Concepts (Fd (..), Error, Count (countNat))+import SocketActivation.Env (getEnv')+import SocketActivation.IO (IO' (IO', run)) --- | Get a list of file descriptors for the sockets.+{-| Get a list of file descriptors for the sockets -} getFileDescriptorList :: IO (Either Error [Fd]) getFileDescriptorList = run (getCount >>= enumerateFds) where
src/SocketActivation/GetSockets.hs view
@@ -1,17 +1,17 @@ module SocketActivation.GetSockets where -import Control.Monad (Monad ((>>=)))-import Control.Monad.IO.Class (MonadIO (liftIO))-import Data.Either (Either)-import Data.Function ((.))-import Data.Traversable (Traversable (traverse))-import System.IO (IO)+import Control.Monad (Monad ((>>=)))+import Control.Monad.IO.Class (MonadIO (liftIO))+import Data.Either (Either)+import Data.Function ((.))+import Data.Traversable (Traversable (traverse))+import System.IO (IO) -import qualified Network.Socket as Net+import qualified Network.Socket as Net -import SocketActivation.Concepts-import SocketActivation.GetFileDescriptors-import SocketActivation.IO+import SocketActivation.Concepts (Socket, Fd (..), Error)+import SocketActivation.GetFileDescriptors (getFileDescriptorList)+import SocketActivation.IO (IO' (IO', run)) getSocketList :: IO (Either Error [Socket]) getSocketList = run (getFds >>= convertToSockets)
src/SocketActivation/IO.hs view
@@ -1,14 +1,14 @@ module SocketActivation.IO where -import Control.Applicative (Applicative)-import Control.Monad (Functor, Monad (return))-import Control.Monad.IO.Class (MonadIO)-import Control.Monad.Trans.Except (ExceptT (..))-import Data.Either (Either (Left))-import Data.Function ((.))-import System.IO (IO)+import Control.Applicative (Applicative)+import Control.Monad (Functor, Monad (return))+import Control.Monad.IO.Class (MonadIO)+import Control.Monad.Trans.Except (ExceptT (..))+import Data.Either (Either (Left))+import Data.Function ((.))+import System.IO (IO) -import SocketActivation.Concepts+import SocketActivation.Concepts (Error) newtype IO' a = IO' { run :: IO (Either Error a) } deriving (Functor, Applicative, Monad, MonadIO) via ExceptT Error IO
src/SocketActivation/Parsing.hs view
@@ -1,18 +1,17 @@ module SocketActivation.Parsing where -import Control.Monad (Functor (fmap), Monad (return),- (>=>))-import Data.Bits (toIntegralSized)-import Data.Function ((.))-import Data.Maybe (Maybe)-import Data.Text (Text)-import Foreign.C.Types (CInt)-import Numeric.Natural (Natural)-import Text.Read (readMaybe)+import Control.Monad (Functor (fmap), Monad (return), (>=>))+import Data.Bits (toIntegralSized)+import Data.Function ((.))+import Data.Maybe (Maybe)+import Data.Text (Text)+import Foreign.C.Types (CInt)+import Numeric.Natural (Natural)+import Text.Read (readMaybe) -import qualified Data.Text as Text+import qualified Data.Text as Text -import SocketActivation.Concepts+import SocketActivation.Concepts readRecipient :: Text -> Maybe Recipient readRecipient = read >=> wrap
systemd-socket-activation.cabal view
@@ -1,21 +1,15 @@ cabal-version: 3.0 name: systemd-socket-activation-version: 1.0.0.1+version: 1.0.0.2 category: System, Network synopsis: Let systemd bind the server's socket for you -description:- "Socket activation" is the a feature of systemd.-- https://www.freedesktop.org/software/systemd/man/sd_listen_fds_with_names.html-- We use it for web servers, to avoid the momentary downtime- that otherwise occurs while restarting processes.- Because the socket is manged by systemd, not by our process,- the socket remains even while our process is down.- Requests to the socket are queued until our process comes- back up to respond.+description: "Socket activation" is the a feature of systemd. We use it for web+ servers, to avoid the momentary downtime that otherwise occurs while restarting+ processes. Because the socket is manged by systemd, not by our process, the+ socket remains even while our process is down. Requests to the socket are queued+ until our process comes back up to respond. copyright: 2021 Mission Valley Software LLC license: MIT@@ -27,7 +21,7 @@ homepage: https://github.com/typeclasses/systemd-socket-activation bug-reports: https://github.com/typeclasses/systemd-socket-activation/issues -build-type: Simple+extra-source-files: *.md source-repository head type: git@@ -56,9 +50,9 @@ SocketActivation.Parsing build-depends:- base ^>= 4.14 || ^>= 4.15 || ^>= 4.16- , containers ^>= 0.6- , network ^>= 3.1- , text ^>= 1.2.3+ , base ^>= 4.14 || ^>= 4.15 || ^>= 4.16 || ^>= 4.17+ , containers ^>= 0.6.4+ , network ^>= 3.1.2+ , text ^>= 1.2.4 || ^>= 2.0 , transformers ^>= 0.5.6 || ^>= 0.6 , unix ^>= 2.7.2