libraft-0.3.0.0: src/Examples/Raft/Socket/Node.hs
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Examples.Raft.Socket.Node where
import Protolude
import Control.Monad.Fail
import Control.Monad.Catch
import Control.Monad.Trans.Class
import Control.Concurrent.STM.TChan
import qualified Data.Serialize as S
import qualified Network.Simple.TCP as NS
import Network.Simple.TCP
import Examples.Raft.Socket.Common
import Raft.Client
import Raft.Event
import Raft.Log
import Raft.Monad
import Raft.Persistent
import Raft.RPC
import Raft.StateMachine
import Raft.Types
--------------------------------------------------------------------------------
-- Network
--------------------------------------------------------------------------------
data NodeSocketEnv v = NodeSocketEnv
{ nsMsgQueue :: TChan (RPCMessage v)
, nsClientReqQueue :: TChan (ClientRequest v)
}
newtype RaftSocketT v m a = RaftSocketT { unRaftSocketT :: ReaderT (NodeSocketEnv v) m a }
deriving (Functor, Applicative, Monad, MonadIO, MonadFail, MonadReader (NodeSocketEnv v), Alternative, MonadPlus, MonadTrans)
deriving instance MonadThrow m => MonadThrow (RaftSocketT v m)
deriving instance MonadCatch m => MonadCatch (RaftSocketT v m)
deriving instance MonadMask m => MonadMask (RaftSocketT v m)
--------------------
-- Raft Instances --
--------------------
instance (MonadMask m, MonadCatch m, MonadIO m, S.Serialize sm, S.Serialize v) => RaftSendClient (RaftSocketT v m) sm v where
sendClient clientId@(ClientId nid) msg = do
let (cHost, cPort) = nidToHostPort (toS nid)
eRes <- Control.Monad.Catch.try $
connect cHost cPort $ \(cSock, _cSockAddr) ->
send cSock (S.encode msg)
case eRes of
Left (err :: SomeException) -> putText ("Failed to send Client: " <> show err)
Right _ -> pure ()
instance (MonadIO m, S.Serialize v) => RaftRecvClient (RaftSocketT v m) v where
type RaftRecvClientError (RaftSocketT v m) v = Text
receiveClient = do
cReq <- asks nsClientReqQueue
fmap Right . liftIO . atomically $ readTChan cReq
instance (MonadCatch m, MonadMask m, MonadIO m, S.Serialize v, Show v) => RaftSendRPC (RaftSocketT v m) v where
sendRPC nid msg = do
eRes <- Control.Monad.Catch.try $
connect host port $ \(sock,_) -> do
NS.send sock (S.encode $ RPCMessageEvent msg)
case eRes of
Left (err :: SomeException) -> putText ("Failed to send RPC: " <> show err)
Right _ -> pure ()
where
(host, port) = nidToHostPort nid
instance (MonadIO m, Show v) => RaftRecvRPC (RaftSocketT v m) v where
type RaftRecvRPCError (RaftSocketT v m) v = Text
receiveRPC = do
msgQueue <- asks nsMsgQueue
fmap Right . liftIO . atomically $ readTChan msgQueue
runRaftSocketT :: MonadIO m => NodeSocketEnv v -> RaftSocketT v m a -> m a
runRaftSocketT nodeSocketEnv = flip runReaderT nodeSocketEnv . unRaftSocketT
acceptConnections
:: forall v m. (S.Serialize v, MonadIO m)
=> HostName
-> ServiceName
-> RaftSocketT v m ()
acceptConnections host port = do
socketEnv@NodeSocketEnv{..} <- ask
serve (Host host) port $ \(sock, _) -> do
mVal <- recvSerialized sock
case mVal of
Nothing -> putText "Socket was closed on the other end"
Just val ->
case val of
ClientRequestEvent req ->
atomically $ writeTChan nsClientReqQueue req
RPCMessageEvent msg ->
atomically $ writeTChan nsMsgQueue msg
newSock :: HostName -> ServiceName -> IO Socket
newSock host port =
listen (Host host) port (pure . fst)
--------------------------------------------------------------------------------
-- Inherited Instances
--------------------------------------------------------------------------------
instance (MonadIO m, RaftPersist m) => RaftPersist (RaftSocketT v m) where
type RaftPersistError (RaftSocketT v m) = RaftPersistError m
initializePersistentState = lift initializePersistentState
writePersistentState ps = lift $ writePersistentState ps
readPersistentState = lift readPersistentState
instance (MonadIO m, RaftInitLog m v) => RaftInitLog (RaftSocketT v m) v where
type RaftInitLogError (RaftSocketT v m) = RaftInitLogError m
initializeLog p = lift $ initializeLog p
instance RaftWriteLog m v => RaftWriteLog (RaftSocketT v m) v where
type RaftWriteLogError (RaftSocketT v m) = RaftWriteLogError m
writeLogEntries entries = lift $ writeLogEntries entries
instance RaftReadLog m v => RaftReadLog (RaftSocketT v m) v where
type RaftReadLogError (RaftSocketT v m) = RaftReadLogError m
readLogEntry idx = lift $ readLogEntry idx
readLastLogEntry = lift readLastLogEntry
instance RaftDeleteLog m v => RaftDeleteLog (RaftSocketT v m) v where
type RaftDeleteLogError (RaftSocketT v m) = RaftDeleteLogError m
deleteLogEntriesFrom idx = lift $ deleteLogEntriesFrom idx
instance RaftStateMachine m sm v => RaftStateMachine (RaftSocketT v m) sm v where
validateCmd = lift . validateCmd
askRaftStateMachinePureCtx = lift askRaftStateMachinePureCtx
instance MonadRaftChan v m => MonadRaftChan v (RaftSocketT v m) where
type RaftEventChan v (RaftSocketT v m) = RaftEventChan v m
readRaftChan = lift . readRaftChan
writeRaftChan chan = lift . writeRaftChan chan
newRaftChan = lift (newRaftChan @v @m)
instance (MonadIO m, MonadRaftFork m) => MonadRaftFork (RaftSocketT v m) where
type RaftThreadId (RaftSocketT v m) = RaftThreadId m
raftFork m = do
persistFile <- ask
lift $ raftFork (runRaftSocketT persistFile m)