content: module GitHUD.Daemon.Network (
    sendOnSocket,
    receiveOnSocket,
    ) where
  
  import Control.Concurrent (forkFinally)
  import qualified Control.Exception as E
  import Control.Monad (forever, void, when)
  import qualified Data.ByteString as S
  import qualified Data.ByteString.UTF8 as BSU
  import Network.Socket (Family(AF_UNIX), socket, defaultProtocol, Socket, SocketType(Stream), close, listen, accept, bind, SockAddr(SockAddrUnix), connect)
  import Network.Socket.ByteString (recv, sendAll)
  import System.Directory (removeFile)
  import System.Posix.Files (fileExist)
  
  sendOnSocket :: FilePath
               -> String
               -> IO ()
  sendOnSocket socketPath msg =
    E.bracket open mClose (mTalkOnClientSocket msg)
    where
      open = do
          socketExists <- fileExist socketPath
          if socketExists
            then do
              sock <- socket AF_UNIX Stream defaultProtocol
              connect sock (SockAddrUnix socketPath)
              return $ Just sock
            else return Nothing
      mClose = maybe (return ()) close
  
  mTalkOnClientSocket :: String
                      -> Maybe Socket
                      -> IO ()
  mTalkOnClientSocket _ Nothing = return ()
  mTalkOnClientSocket msg (Just sock) = sendAll sock $ BSU.fromString msg
  
  receiveOnSocket :: FilePath
                  -> (String -> IO m)
                  -> IO ()
  receiveOnSocket socketPath withMessageCb = do
    socketExists <- fileExist socketPath
    when socketExists (removeFile socketPath)
    E.bracket open close loop
    where
      open = do
        sock <- socket AF_UNIX Stream defaultProtocol
        bind sock (SockAddrUnix socketPath)
        listen sock 1
        return sock
      loop sock = forever $ do
        (conn, peer) <- accept sock
        void $ forkFinally (talk conn) (\_ -> close conn)
      talk conn = (readPacket conn "") >>= withMessageCb
      readPacket conn acc = do
        msg <- recv conn 1024
        if (S.null msg)
          then return acc
          else readPacket conn (acc ++ (BSU.toString msg))
  