packages feed

network-service-0.1.0.0: Example/Echo.hs

{-# LANGUAGE Rank2Types #-}
--------------------------------------------------------------------------------
-- |
-- Module      : Example.Echo
-- Copyright   : (c) Moritz Angermann 2014
-- License     : MIT
--
-- Maintainer  : moritz@lichtzwerge.de
-- Stability   : stable
-- Portability : portable
--
-- An echo service on port 2000
--
-- To start the server run
-- > $ echo server
--
-- You can then run the client
-- > $ echo client
--
-- Or connect to the server with telnet
-- > $ telnet localhost 2000
--
--------------------------------------------------------------------------------
module Main (main) where
import           Network.Simple.TCP
import           Data.ByteString.Char8   ( pack, unpack )
import           System.Environment      ( getProgName, getArgs )
import           Control.Monad           ( unless )

import Network.Service
import Network.Transport.Encoding.Base64 (mkService)

-- | Make a service server running on the executing host.
mkServiceServer :: ServiceMessage a
                   => ServiceName      -- ^ the port
                   -> ServiceHandler a -- ^ a handler to handle connections.
                   -> IO ()
mkServiceServer port shandler = serve HostAny port handler
  where handler :: (Socket, SockAddr) -> IO ()
        handler x = mkService x >>= shandler

-- | Make a service client
mkServiceClient :: ServiceMessage a
                   => HostName       -- ^ The hostname that provides a 'Service a'.
                   -> ServiceName    -- ^ The port the service runs at.
                   -> IO (Service a) -- ^ The client. (Service interface)
mkServiceClient h p = connect h p mkService

-- | We use a simple data type for communication.
--   All it holds is a simple string.
data Message = Msg String

-- | Turning a String message into a bytestring.
--   Trivially through pack and unpack.
instance ServiceMessage Message where
  toBS (Msg s) = pack s
  fromBS = Msg . unpack

main :: IO ()
main = do
  args <- getArgs
  prog <- getProgName
  
  case args of
    ["server"] -> mkServiceServer "2000" handler
    ["client"] -> do
      service <- mkServiceClient "localhost" "2000"
      let msg = "Hello World!"
      putStrLn $ "[Client] Sending: " ++ msg
      sSend service $ Msg msg
      Msg resp <- sRecv service
      putStrLn $ "[Client] Received: " ++ resp
      sTerm service
    _          -> putStrLn $ "Usage: " ++ prog ++ " (server|client)"

  where handler :: ServiceHandler Message
        handler service = sRecv service >>= sSend service >> sDone service >>= flip unless (handler service)