content: -----------------------------------------------------------------------------
  -- |
  -- Module      :  NgxExport.Tools.System
  -- Copyright   :  (c) Alexey Radkov 2018-2023
  -- License     :  BSD-style
  --
  -- Maintainer  :  alexey.radkov@gmail.com
  -- Stability   :  stable
  -- Portability :  non-portable (requires POSIX)
  --
  -----------------------------------------------------------------------------
  
  
  module NgxExport.Tools.System (
      -- * Various functions to access low-level Nginx API
      -- $description
  
      -- * Exported functions
                                 terminateWorkerProcess
                                ,restartWorkerProcess
                                ,finalizeHTTPRequest
                                ,workerProcessIsExiting
                                ,ngxRequestPtr
                                ,ngxNow
                                ,ngxPid
                                ) where
  
  import           NgxExport
  
  import           Foreign.Ptr
  import           Foreign.Storable
  import           Foreign.C.Types
  import           Data.ByteString (ByteString)
  import qualified Data.ByteString.Lazy as L
  import           Data.Binary.Get
  import           Data.Maybe
  import           Control.Exception
  import           System.Posix.Types
  
  -- $description
  --
  -- Various functions to access low-level Nginx API, mostly wrappers around
  -- corresponding functions and data from module "NgxExport".
  
  -- | Terminates the Nginx worker process from a Haskell service.
  --
  -- Nginx master process shall /not/ spawn a new worker process thereafter. This
  -- function throws exception 'TerminateWorkerProcess', and therefore terminates
  -- the worker process effectively only from a Haskell service.
  terminateWorkerProcess :: String -> IO a
  terminateWorkerProcess = throwIO . TerminateWorkerProcess
  
  -- | Restarts the Nginx worker process from a Haskell service.
  --
  -- Nginx master process shall spawn a new worker process after termination of
  -- the current one. This function throws exception 'RestartWorkerProcess', and
  -- therefore terminates the worker process effectively only from a Haskell
  -- service.
  restartWorkerProcess :: String -> IO a
  restartWorkerProcess = throwIO . RestartWorkerProcess
  
  -- | Finalizes the current HTTP request from a Haskell asynchronous variable
  --   handler.
  --
  -- This function throws exception 'FinalizeHTTPRequest', and therefore
  -- terminates the HTTP request effectively only from a Haskell asynchronous
  -- variable handler.
  finalizeHTTPRequest :: Int -> Maybe String -> IO a
  finalizeHTTPRequest = (throwIO .) . FinalizeHTTPRequest
  
  -- | Checks that a generic exception is of type 'WorkerProcessIsExiting'.
  --
  -- This can be useful to check quickly in an exception handler whether a
  -- Haskell service has been interrupted because the worker process is exiting.
  workerProcessIsExiting :: SomeException -> Bool
  workerProcessIsExiting e =
      isJust (fromException e :: Maybe WorkerProcessIsExiting)
  
  -- | Unmarshals the value of Nginx variable __/$_r_ptr/__ into a pointer to
  --   the Nginx request object.
  --
  -- This is safe to use in request-based Haskell handlers such as synchronous
  -- and asynchronous tasks and content handlers, but not in services and their
  -- derivatives. In /asynchronous/ tasks and content handlers the value must be
  -- used as read-only. The value can be passed into a /C plugin/, however, as
  -- opposed to usual functions in Nginx C code, it must be tested against the
  -- /NULL/ value.
  ngxRequestPtr :: ByteString -> Ptr ()
  ngxRequestPtr = wordPtrToPtr . fromIntegral . runGet getWordhost . L.fromStrict
  
  -- | Returns the current time as the number of seconds elapsed since the UNIX
  --   epoch.
  --
  -- The value is taken from Nginx core, so no additional system calls get
  -- involved. On the other hand, it means that this is only safe to use from
  -- an Nginx worker's main thread, i.e. in /synchronous/ Haskell handlers and
  -- /service hooks/. Be also aware that this is a small type casting hack:
  -- the value is interpreted as being of type @time_t@ while having been
  -- actually wrapped in a bigger C struct as its first element.
  ngxNow :: IO CTime
  ngxNow = ngxCachedTimePtr >>= peek >>= peek . castPtr
  
  -- | Returns the /PID/ of the current worker process cached in Nginx core.
  ngxPid :: IO CPid
  ngxPid = ngxCachedPid
  
  