module GitHUD.Daemon.Network (
  sendOnSocket,
  fromSocket
  ) where

import Control.Concurrent (forkFinally)
import qualified Control.Exception as E
import Control.Monad (forever, void)
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.Posix.Files (fileExist)

sendOnSocket :: FilePath
             -> String
             -> IO Bool
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 Bool
mTalkOnClientSocket _ Nothing = return False
mTalkOnClientSocket msg (Just sock) = do
    sendAll sock $ BSU.fromString msg
    return True

fromSocket :: FilePath
           -> (String -> IO m)
           -> IO ()
fromSocket socketPath withMessageCb = 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))