module Ouroboros.Consensus.Util.FileLock
  ( FileLock (..)
  , ioFileLock
  ) where

import qualified System.FileLock as IO

-- | Abstraction for file locks
data FileLock m = FileLock
  { forall (m :: * -> *). FileLock m -> FilePath -> m (m ())
lockFile :: FilePath -> m (m ())
  -- ^ Obtain an exclusive lock on the given file.
  --
  -- Returns the function to unlock the file.
  --
  -- Blocks until the lock is available.
  --
  -- We don't guarantee the ability to read/write to a locked file, not
  -- even when holding the lock.
  }

-- | Implementation of 'FileLock' for 'IO', using on "System.FileLock".
--
-- Locking the file can block in FFI, so not interruptible.
--
-- Unlocking the file is not guaranteed to be synchronous. Near instantaneous
-- on Linux, but not synchronous. On Windows, unlocking is even more lazy.
ioFileLock :: FileLock IO
ioFileLock :: FileLock IO
ioFileLock =
  FileLock
    { lockFile :: FilePath -> IO (IO ())
lockFile = \FilePath
fp ->
        FileLock -> IO ()
IO.unlockFile (FileLock -> IO ()) -> IO FileLock -> IO (IO ())
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> FilePath -> SharedExclusive -> IO FileLock
IO.lockFile FilePath
fp SharedExclusive
IO.Exclusive
    }