module Development.Duplo.Watcher where
import Control.Concurrent (ThreadId (..), forkFinally, forkIO,
killThread, threadDelay)
import Control.Concurrent.Chan (Chan, getChanContents, newChan,
readChan)
import Control.Exception (try)
import Control.Monad (forever, unless, void, when)
import Data.Foldable (forM_)
import Data.IORef (IORef, newIORef, readIORef,
writeIORef)
import Data.Maybe (fromJust, isJust)
import Data.String (fromString)
import System.FilePath.Posix (FilePath)
import System.FSNotify (Action, Debounce (..), Event,
WatchConfig (..), watchTreeChan,
withManagerConf)
watch :: IO () -> [FilePath] -> IO ()
watch onChange paths = do
let watchConfig = WatchConfig { confDebounce = NoDebounce
, confPollInterval = 100000
, confUsePolling = False
}
tidVar <- newIORef (Nothing :: Maybe ThreadId)
chan <- newChan :: IO (Chan Event)
let chanStream = getChanContents chan
let exceptionHandler _ = return ()
let handler = forkFinally onChange exceptionHandler
let handleEvent' = handleEvent tidVar handler
forkIO $ chanStream >>= mapM_ (handleEvent' . Just)
withManagerConf watchConfig $ \manager -> do
let paths' = fmap fromString paths
let always = const True
let watch' p = watchTreeChan manager p always chan
void $ handleEvent' Nothing
mapM_ watch' paths'
forever $ threadDelay $ 1000000 * 60 * 60 * 24 * 365
handleEvent :: IORef (Maybe ThreadId) -> IO ThreadId -> Maybe Event -> IO ()
handleEvent tidVar handler _ = do
tid <- readIORef tidVar
forM_ tid killThread
newTid <- handler
writeIORef tidVar $ Just newTid