module Development.Duplo.Watcher where
import Control.Concurrent (threadDelay, forkIO, forkFinally, ThreadId(..), killThread)
import Control.Concurrent.Chan (Chan, newChan, readChan, getChanContents)
import Control.Exception (try)
import Control.Monad (forever, void, when, unless)
import Data.Foldable (forM_)
import Data.IORef (newIORef, readIORef, writeIORef, IORef)
import Data.Maybe (isJust, fromJust)
import Data.String (fromString)
import System.FSNotify (withManagerConf, watchTreeChan, WatchConfig(..), Debounce(..), Action, Event)
import System.FilePath.Posix (FilePath)
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