packages feed

time-warp-1.1.1.0: examples/ping-pong/Main.hs

{-# LANGUAGE DeriveAnyClass  #-}
{-# LANGUAGE OverloadedLists #-}

-- | Example of simple ping-pong network application.

module Main where

import           Control.Concurrent       (forkIO)
import           Control.Monad            (void)
import           Control.Monad.IO.Class   (MonadIO (liftIO))

import           Data.Binary              (Binary)
import           Data.Data                (Data)
import           Data.Default             (def)
import           Data.Time.Clock          (getCurrentTime)

import           Formatting               (sformat, shown, (%))
import           GHC.Generics             (Generic)
import           Serokell.Util.Concurrent (threadDelay)
import           System.Wlog              (LoggerConfig (..), LoggerName, Severity (Info),
                                           logInfo, traverseLoggerConfig, usingLoggerName)

import           Control.TimeWarp.Rpc     (BinaryP, Binding (AtPort), Dialog,
                                           Listener (..), Message (..), Transfer, listen,
                                           localhost, messageName', plainBinaryP,
                                           runDialog, runTransfer, send)
import           Control.TimeWarp.Timed   (for, runTimedIO, sec, wait)

runNode :: LoggerName -> Dialog (BinaryP ()) (Transfer ()) () -> IO ()
runNode name = void . forkIO . runTimedIO . usingLoggerName name . runTransfer (pure ())
             . runDialog plainBinaryP

ppLoggerConfig :: LoggerConfig
ppLoggerConfig = def { lcSubloggers = [("ping", infoConf), ("pong", infoConf)] }
  where
    infoConf = def { lcSeverity = Just Info }

initLogging :: MonadIO m => m ()
initLogging = traverseLoggerConfig id ppLoggerConfig Nothing

data Ping = Ping
    deriving (Generic, Binary, Data)

data Pong = Pong
    deriving (Generic, Binary, Data)

instance Message Ping where
    formatMessage = messageName'

instance Message Pong where
    formatMessage = messageName'

main :: IO ()
main = do
    initLogging

    runNode "ping" $ do
        logInfo "Running..."

        wait (for 2 sec)
        send (localhost, 5555) Ping

        void $ listen (AtPort 4444)
            [ Listener $ \Pong -> do
                curTime <- liftIO getCurrentTime
                logInfo $ sformat ("Get Pong at "%shown) curTime
            ]

    runNode "pong" $ do
        logInfo "Running..."

        void $ listen (AtPort 5555)
            [ Listener $ \Ping -> do
                curTime <- liftIO getCurrentTime
                logInfo $ sformat ("Get Ping at "%shown) curTime
                send (localhost, 4444) Pong
            ]

    threadDelay $ sec 5