module Language.Erlang.LocalNode ( LocalNode()
, newLocalNode
, make_pid
, make_ref
, make_port
, make_mailbox
, closeLocalNode
)
where
import Prelude hiding (id)
import Control.Concurrent.STM
import qualified Data.ByteString as BS
import Data.Word
import Util.IOx
import Util.BufferedSocket
import Language.Erlang.NodeState
import Language.Erlang.NodeData
import Language.Erlang.Epmd
import Language.Erlang.Handshake
import Language.Erlang.Term
import Language.Erlang.ControlMessage
import Language.Erlang.Connection
import Language.Erlang.Mailbox
data LocalNode = LocalNode { nodeData :: NodeData
, dFlags :: DistributionFlags
, hostName :: BS.ByteString
, sock :: BufferedSocket
, creation :: Word8
, nodeState :: NodeState Term Term Mailbox Connection
, cookie :: BS.ByteString
}
newLocalNode :: Term -> BS.ByteString -> IOx LocalNode
newLocalNode nodeName cookie = do
let (aliveName, hostName) = splitNodeName nodeName
nodeData = NodeData 0 HiddenNode TcpIpV4 R6B R6B aliveName ""
localFlags = [EXTENDED_REFERENCES, EXTENDED_PIDS_PORTS, BIT_BINARIES, NEW_FLOATS, FUN_TAGS, NEW_FUN_TAGS]
(sock, creation) <- registerNode nodeData hostName
LocalNode <$>
pure nodeData <*>
pure localFlags <*>
pure hostName <*>
pure sock <*>
pure (fromIntegral creation) <*>
newNodeState <*>
pure cookie
getNodeName :: LocalNode -> BS.ByteString
getNodeName LocalNode {nodeData = NodeData {aliveName = aliveName}, hostName = hostName} = aliveName `BS.append` "@" `BS.append` hostName
make_pid :: LocalNode -> IOx Term
make_pid localNode@LocalNode {creation = creation, nodeState = nodeState} = do
(id, serial) <- new_pid nodeState
return $ pid (getNodeName localNode) id serial creation
make_ref :: LocalNode -> IOx Term
make_ref localNode@LocalNode {creation = creation, nodeState = nodeState} = do
(refId0, refId1, refId2) <- new_ref nodeState
return $ ref (getNodeName localNode) creation [refId0, refId1, refId2]
make_port :: LocalNode -> IOx Term
make_port localNode@LocalNode {creation = creation, nodeState = nodeState} = do
id <- new_port nodeState
return $ port (getNodeName localNode) id creation
make_mailbox :: LocalNode -> IOx Mailbox
make_mailbox localNode@LocalNode {nodeData = nodeData, dFlags = dFlags, nodeState = nodeState, cookie = cookie} = do
self <- make_pid localNode
queue <- toIOx newTQueueIO
let mailbox = newMailbox nodeState self queue make_connection
putMailboxForPid nodeState self mailbox
return mailbox
where
make_connection :: Term -> IOx Connection
make_connection remoteName = do
connectNodes (getNodeName localNode) nodeData dFlags remoteName cookie nodeState
newMailbox :: NodeState Term Term Mailbox Connection -> Term -> TQueue Term -> (Term -> IOx Connection) -> Mailbox
newMailbox nodeState self queue connect = do
Mailbox
self
_deliverLink
_deliverSend
_deliverExit
_deliverUnlink
_deliverRegSend
_deliverGroupLeader
_deliverExit2
_sendReg
_receive
where
_deliverLink :: Term -> IOx ()
_deliverLink _fromPid = do
undefined
_deliverSend :: Term -> IOx ()
_deliverSend message = do
atomicallyX $ writeTQueue queue message
_deliverExit :: Term -> Term -> IOx ()
_deliverExit _fromPid _reason = do
undefined
_deliverUnlink :: Term -> IOx ()
_deliverUnlink _fromPid = do
undefined
_deliverRegSend :: Term -> Term -> IOx ()
_deliverRegSend _fromPid _message = do
undefined
_deliverGroupLeader :: Term -> IOx ()
_deliverGroupLeader _fromPid = do
undefined
_deliverExit2 :: Term -> Term -> IOx ()
_deliverExit2 _fromPid _reason = do
undefined
_sendReg :: Term -> Term -> Term -> IOx ()
_sendReg regName nodeName message = do
connection <- getConnectionForNode nodeState nodeName `catchX` const (connect nodeName)
sendControlMessage connection $ REG_SEND self regName message
_receive :: IOx Term
_receive = do
atomicallyX $ readTQueue queue
closeLocalNode :: LocalNode -> IOx ()
closeLocalNode LocalNode {nodeState = nodeState, sock = sock } = do
socketClose sock
getConnectedNodes nodeState >>= mapM_ (closeConnection . snd)