mirror of https://github.com/voidlizard/hbs2
179 lines
5.0 KiB
Haskell
179 lines
5.0 KiB
Haskell
{-# Language TemplateHaskell #-}
|
|
module Main where
|
|
|
|
import HBS2.Prelude.Plated
|
|
import HBS2.Net.Proto.Types
|
|
import HBS2.Clock
|
|
import HBS2.Net.Messaging.TCP
|
|
import HBS2.Actors.Peer
|
|
|
|
import HBS2.System.Logger.Simple
|
|
|
|
import System.IO
|
|
import Control.Monad.Reader
|
|
import Control.Monad.Writer hiding (listen)
|
|
|
|
import Test.Tasty.HUnit
|
|
|
|
import Data.ByteString.Lazy (ByteString)
|
|
import Control.Concurrent.Async
|
|
import Lens.Micro.Platform
|
|
import Codec.Serialise
|
|
import System.Environment
|
|
|
|
tracePrefix :: SetLoggerEntry
|
|
tracePrefix = logPrefix "[trace] "
|
|
|
|
debugPrefix :: SetLoggerEntry
|
|
debugPrefix = logPrefix "[debug] "
|
|
|
|
errorPrefix :: SetLoggerEntry
|
|
errorPrefix = logPrefix "[error] "
|
|
|
|
warnPrefix :: SetLoggerEntry
|
|
warnPrefix = logPrefix "[warn] "
|
|
|
|
noticePrefix :: SetLoggerEntry
|
|
noticePrefix = logPrefix "[RT] "
|
|
|
|
|
|
data PingPong e = Ping Int
|
|
| Pong Int
|
|
deriving stock (Eq,Generic,Show,Read)
|
|
|
|
|
|
instance Serialise (PingPong e)
|
|
|
|
instance HasProtocol L4Proto (PingPong L4Proto) where
|
|
type instance ProtocolId (PingPong L4Proto) = 1
|
|
type instance Encoded L4Proto = ByteString
|
|
decode = either (const Nothing) Just . deserialiseOrFail
|
|
encode = serialise
|
|
|
|
testCmd :: forall a ann b m . ( Pretty a
|
|
, Pretty b
|
|
, MonadIO m
|
|
)
|
|
=> a -> Doc ann -> b -> m ()
|
|
|
|
testCmd p1 s p2 = do
|
|
notice $ brackets (pretty p1)
|
|
<+> s
|
|
<+> parens (pretty p2)
|
|
|
|
pingPongHandler :: forall e m proto . ( MonadIO m
|
|
, Response e (PingPong e) m
|
|
, HasProtocol e (PingPong e)
|
|
, HasOwnPeer e m
|
|
, HasDeferred proto e m
|
|
, Pretty (Peer e)
|
|
, proto ~ PingPong e
|
|
)
|
|
=> Int
|
|
-> PingPong e
|
|
-> m ()
|
|
|
|
pingPongHandler _ req = do
|
|
|
|
that <- thatPeer (Proxy @proto)
|
|
own <- ownPeer @e
|
|
|
|
case req of
|
|
|
|
Ping c -> do
|
|
testCmd own ("RECV PING <<<" <+> pretty c) that
|
|
|
|
deferred @proto do
|
|
pause @'Seconds 1
|
|
testCmd own ("SEND PONG >>>" <+> pretty (succ c)) that
|
|
response (Pong @e (succ c))
|
|
|
|
Pong c -> do
|
|
testCmd own ("RECV PONG <<<" <+> pretty c) that
|
|
|
|
deferred @proto do
|
|
pause @'Seconds 1
|
|
testCmd own ("SEND PING >>>" <+> pretty (succ c)) that
|
|
response (Ping @e c)
|
|
|
|
data PPEnv =
|
|
PPEnv
|
|
{ _ppSelf :: Peer L4Proto
|
|
, _ppFab :: Fabriq L4Proto
|
|
}
|
|
|
|
makeLenses 'PPEnv
|
|
|
|
newtype PingPongM e m a = PingPongM { fromPingPong :: ReaderT PPEnv m a }
|
|
deriving newtype ( Functor
|
|
, Applicative
|
|
, Monad
|
|
, MonadIO
|
|
, MonadReader PPEnv
|
|
, MonadTrans
|
|
)
|
|
|
|
runPingPong :: (MonadIO m, PeerMessaging L4Proto) => Peer L4Proto -> Fabriq L4Proto -> PingPongM L4Proto m a -> m a
|
|
runPingPong peer tcp m = runReaderT (fromPingPong m) (PPEnv peer tcp)
|
|
|
|
instance Monad m => HasFabriq L4Proto (PingPongM L4Proto m) where
|
|
getFabriq = asks (view ppFab)
|
|
|
|
instance Monad m => HasOwnPeer L4Proto (PingPongM L4Proto m) where
|
|
ownPeer = asks (view ppSelf)
|
|
|
|
instance HasTimeLimits L4Proto (PingPong L4Proto) IO where
|
|
tryLockForPeriod _ _ = pure True
|
|
|
|
|
|
instance HasDeferred (PingPong L4Proto) L4Proto (ResponseM L4Proto (PingPongM L4Proto IO)) where
|
|
deferred m = do
|
|
self <- lift $ asks (view ppSelf)
|
|
bus <- lift $ asks (view ppFab)
|
|
who <- thatPeer (Proxy @(PingPong L4Proto))
|
|
void $ liftIO $ async $ runPingPong self bus (runResponseM who m)
|
|
|
|
main :: IO ()
|
|
main = do
|
|
hSetBuffering stdout LineBuffering
|
|
hSetBuffering stderr LineBuffering
|
|
|
|
setLogging @DEBUG debugPrefix
|
|
setLogging @INFO defLog
|
|
setLogging @ERROR errorPrefix
|
|
setLogging @WARN warnPrefix
|
|
setLogging @NOTICE noticePrefix
|
|
setLogging @TRACE tracePrefix
|
|
|
|
args <- getArgs >>= \case
|
|
[self,remote] -> pure (self,remote)
|
|
_ -> error "bad args"
|
|
|
|
let self = fromString (fst args) -- "tcp://127.0.0.1:3001"
|
|
remote <- fromPeerAddr $ fromString (snd args) :: IO (Peer L4Proto)
|
|
|
|
tcp <- newMessagingTCP self
|
|
|
|
peer <- async do
|
|
runMessagingTCP tcp
|
|
|
|
-- setLoggingOff @TRACE
|
|
|
|
pp1 <- async $ runPingPong (view tcpOwnPeer tcp) (Fabriq tcp) do
|
|
testCmd (view tcpOwnPeer tcp) ("!!! SEND PING" <+> pretty 1) remote
|
|
request remote (Ping @L4Proto 1)
|
|
runProto @L4Proto
|
|
[ makeResponse (pingPongHandler 100)
|
|
]
|
|
|
|
void $ waitAnyCatchCancel [pp1,peer]
|
|
|
|
setLoggingOff @DEBUG
|
|
setLoggingOff @INFO
|
|
setLoggingOff @ERROR
|
|
setLoggingOff @WARN
|
|
setLoggingOff @NOTICE
|
|
setLoggingOff @TRACE
|
|
|
|
|