{-# OPTIONS -Wall -O #-}
{-# LANGUAGE LambdaCase #-}
import           Control.Concurrent (forkIO)
import           Control.Concurrent.Chan (Chan, newChan, writeChan, readChan)
import qualified Data.ByteString as BS
import           System.IO (Handle, stdin, stdout)

handleToChan :: Handle -> Chan (Maybe BS.ByteString) -> IO ()
handleToChan handle chan =
    do
        buf <- BS.hGetSome handle (128*1024)
        if BS.null buf
            then writeChan chan Nothing
            else writeChan chan (Just buf) >> handleToChan handle chan

chanToHandle :: Chan (Maybe BS.ByteString) -> Handle -> IO ()
chanToHandle chan handle =
    readChan chan >>=
    \case
    Nothing -> pure ()
    Just buf -> BS.hPutStr handle buf >> chanToHandle chan handle

main :: IO ()
main = do
    bufs <- newChan
    _tid <- forkIO (stdin `handleToChan` bufs)
    bufs `chanToHandle` stdout