mirror of https://github.com/voidlizard/hbs2
207 lines
5.8 KiB
Haskell
207 lines
5.8 KiB
Haskell
{-# Language TemplateHaskell #-}
|
|
module Main where
|
|
|
|
import HBS2.Prelude.Plated
|
|
import HBS2.Clock
|
|
import HBS2.Net.Proto
|
|
import HBS2.Net.Messaging.Unix
|
|
import HBS2.Actors.Peer
|
|
import HBS2.OrDie
|
|
|
|
import HBS2.System.Logger.Simple
|
|
|
|
import Codec.Serialise
|
|
import Control.Monad.Reader
|
|
import Control.Monad.Trans.Resource
|
|
import Data.ByteString.Lazy (ByteString)
|
|
import Lens.Micro.Platform
|
|
import Prettyprinter
|
|
import System.FilePath.Posix
|
|
import System.IO
|
|
import System.IO.Temp
|
|
import UnliftIO.Async
|
|
import UnliftIO qualified as UIO
|
|
import UnliftIO (TVar)
|
|
|
|
data PingPong e = Ping Int
|
|
| Pong Int
|
|
deriving stock (Eq,Generic,Show,Read)
|
|
|
|
|
|
instance Serialise (PingPong e)
|
|
|
|
|
|
instance HasProtocol UNIX (PingPong UNIX) where
|
|
type instance ProtocolId (PingPong UNIX) = 1
|
|
type instance Encoded UNIX = ByteString
|
|
decode = either (const Nothing) Just . deserialiseOrFail
|
|
encode = serialise
|
|
|
|
pingPongHandlerS :: forall e m . ( MonadIO m
|
|
, Response e (PingPong e) m
|
|
, HasProtocol e (PingPong e)
|
|
, Pretty (Peer e)
|
|
)
|
|
=> TVar [(Peer e, PingPong e)]
|
|
-> Int
|
|
-> PingPong e
|
|
-> m ()
|
|
|
|
pingPongHandlerS tv n msg = do
|
|
|
|
that <- thatPeer (Proxy @(PingPong e))
|
|
|
|
UIO.atomically $ UIO.modifyTVar tv ((that,msg):)
|
|
|
|
case msg of
|
|
|
|
Ping c -> do
|
|
debug ("S: Ping" <+> pretty c <+> "from" <+> pretty that ) >> response (Pong @e c)
|
|
|
|
Pong _ -> pure ()
|
|
|
|
pingPongHandler1 :: forall e m . ( MonadIO m
|
|
, Response e (PingPong e) m
|
|
, HasProtocol e (PingPong e)
|
|
)
|
|
=> TVar [PingPong e]
|
|
-> Int
|
|
-> PingPong e
|
|
-> m ()
|
|
|
|
pingPongHandler1 t n msg = do
|
|
|
|
UIO.atomically $ UIO.modifyTVar t (msg:)
|
|
|
|
case msg of
|
|
|
|
Ping c -> pure ()
|
|
Pong c -> pure ()
|
|
|
|
-- Pong c | c < n -> debug ("C1: Pong" <+> pretty c) >> response (Ping @e (succ c))
|
|
-- | otherwise -> pure ()
|
|
|
|
|
|
pingPongHandler2 :: forall e m . ( MonadIO m
|
|
, Response e (PingPong e) m
|
|
, HasProtocol e (PingPong e)
|
|
)
|
|
=> TVar [PingPong e]
|
|
-> Int
|
|
-> PingPong e
|
|
-> m ()
|
|
|
|
pingPongHandler2 t n msg = do
|
|
|
|
UIO.atomically $ UIO.modifyTVar t (msg:)
|
|
|
|
case msg of
|
|
|
|
Ping c -> pure ()
|
|
Pong c -> pure ()
|
|
|
|
-- Pong c | c < n -> debug ("C2: Pong" <+> pretty c) >> response (Ping @e (succ c))
|
|
-- | otherwise -> pure ()
|
|
|
|
|
|
data PPEnv =
|
|
PPEnv
|
|
{ _ppSelf :: Peer UNIX
|
|
, _ppFab :: Fabriq UNIX
|
|
}
|
|
|
|
makeLenses 'PPEnv
|
|
|
|
newtype PingPongM m a = PingPongM { fromPingPong :: ReaderT PPEnv m a }
|
|
deriving newtype ( Functor
|
|
, Applicative
|
|
, Monad
|
|
, MonadIO
|
|
, MonadUnliftIO
|
|
, MonadReader PPEnv
|
|
, MonadTrans
|
|
)
|
|
|
|
runPingPong :: (MonadIO m, PeerMessaging UNIX) => MessagingUnix -> PingPongM m a -> m a
|
|
runPingPong tran m = runReaderT (fromPingPong m) (PPEnv (msgUnixSelf tran) (Fabriq tran))
|
|
|
|
instance Monad m => HasFabriq UNIX (PingPongM m) where
|
|
getFabriq = asks (view ppFab)
|
|
|
|
instance Monad m => HasOwnPeer UNIX (PingPongM m) where
|
|
ownPeer = asks (view ppSelf)
|
|
|
|
instance HasTimeLimits UNIX (PingPong UNIX) IO where
|
|
tryLockForPeriod _ _ = pure True
|
|
|
|
main :: IO ()
|
|
main = do
|
|
|
|
setLogging @DEBUG (logPrefix "[debug] ")
|
|
setLogging @INFO (logPrefix "")
|
|
setLogging @ERROR (logPrefix "[err] ")
|
|
setLogging @WARN (logPrefix "[warn] ")
|
|
setLogging @NOTICE (logPrefix "[notice] ")
|
|
setLogging @TRACE (logPrefix "[trace] ")
|
|
|
|
liftIO $ hSetBuffering stdout LineBuffering
|
|
liftIO $ hSetBuffering stderr LineBuffering
|
|
|
|
withSystemTempDirectory "test-unix-socket" $ \tmp -> do
|
|
|
|
let soname = tmp </> "unix.socket"
|
|
|
|
server <- newMessagingUnix True 1.0 soname
|
|
|
|
client1 <- newMessagingUnix False 1.0 soname
|
|
client2 <- newMessagingUnix False 1.0 soname
|
|
|
|
m1 <- async $ runMessagingUnix server
|
|
m2 <- async $ runMessagingUnix client1
|
|
m3 <- async $ runMessagingUnix client2
|
|
|
|
trs <- UIO.newTVarIO []
|
|
tr1 <- UIO.newTVarIO []
|
|
tr2 <- UIO.newTVarIO []
|
|
|
|
p1 <- async $ runPingPong server do
|
|
runProto @UNIX
|
|
[ makeResponse (pingPongHandlerS trs 2)
|
|
]
|
|
|
|
-- p2 <- async $ pause @'Seconds 300
|
|
p2 <- async $ runPingPong client1 do
|
|
-- pause @'Seconds 0.25
|
|
-- request (msgUnixSelf server) (Ping @UNIX 0)
|
|
l <- async $ runProto @UNIX
|
|
[ makeResponse (pingPongHandler1 tr1 10)
|
|
]
|
|
link l
|
|
forM_ [1..10] $ \n-> request (msgUnixSelf server) (Ping @UNIX n)
|
|
wait l
|
|
|
|
-- p3 <- async $ pause @'Seconds 300
|
|
p3 <- async $ do
|
|
runPingPong client2 do
|
|
l <- async $ runProto @UNIX
|
|
[ makeResponse (pingPongHandler2 tr2 200)
|
|
]
|
|
link l
|
|
forM_ (take 10 [10000000..]) $ \n-> request (msgUnixSelf server) (Ping @UNIX n)
|
|
wait l
|
|
|
|
-- p4 <- async do
|
|
pause @'Seconds 10
|
|
UIO.readTVarIO trs >>= print . vcat . fmap (\(a,b) -> pretty (a, show b))
|
|
UIO.readTVarIO tr1 >>= print
|
|
UIO.readTVarIO tr2 >>= print
|
|
|
|
cancel m1
|
|
|
|
(_,r) <- liftIO $ waitAnyCatchCancel [m1,m2,m3,p1,p2,p3]
|
|
|
|
debug (viaShow r)
|
|
|
|
|
|
|