{-# OPTIONS_GHC -Wall #-}
{-# LANGUAGE OverloadedStrings #-}
module Socket where
import Control.Monad.Trans (MonadIO(liftIO))
import Control.Concurrent (threadDelay, forkIO, killThread, ThreadId)
import qualified Control.Exception as E
import qualified Data.ByteString.Char8 as BSC
import qualified Filesystem.Path.CurrentOS as FP
import qualified Network.WebSockets as WS
import qualified System.FSNotify.Devel as NDevel
import qualified System.FSNotify as Notify
import qualified Generate
fileChangeApp :: FilePath -> WS.ServerApp
fileChangeApp watchedFile pendingConnection =
do connection <- WS.acceptRequest pendingConnection
Notify.withManager $ \notifyManager -> do
_ <- NDevel.treeExtExists notifyManager "." "elm" (sendHotSwap watchedFile connection)
keepAlive connection
sendHotSwap :: FilePath -> WS.Connection -> FP.FilePath -> IO ()
sendHotSwap watchedFile connection _ =
do result <- liftIO (Generate.js watchedFile)
WS.sendTextData connection (BSC.pack result)
keepAlive :: WS.Connection -> IO ()
keepAlive connection =
loop
where
loop :: IO ()
loop = do
pingThread <- forkIO ping
listen pingThread
ping :: IO ()
ping = do
threadDelay (10 * 1000000) -- 10 seconds
WS.sendPing connection ("ping" :: BSC.ByteString) `E.catch` connectionClosed
connectionClosed :: E.SomeException -> IO ()
connectionClosed _ = return ()
listen :: ThreadId -> IO ()
listen pingThread = do
pong <- WS.receive connection
case pong of
WS.DataMessage _ -> listen pingThread
WS.ControlMessage controlMessage ->
case controlMessage of
WS.Ping _ -> listen pingThread
WS.Pong _ -> loop
WS.Close _ _ ->
killThread pingThread >> return ()