Safe Haskell | None |
---|---|
Language | Haskell2010 |
Cardano.Shell.NodeIPC
Description
Node IPC module. For details please read the spec:
https://github.com/input-output-hk/cardano-shell/blob/develop/specs/CardanoShellSpec.pdf
Synopsis
- newtype Port = Port {}
- data MsgIn
- data MsgOut
- newtype ReadHandle = ReadHandle {}
- newtype WriteHandle = WriteHandle {}
- data ProtocolDuration
- startNodeJsIPC :: ProtocolDuration -> Port -> IO (Either NodeIPCError ())
- startIPC :: ProtocolDuration -> ReadHandle -> WriteHandle -> Port -> IO (Either NodeIPCError ())
- handleIPCProtocol :: Port -> MsgIn -> IO MsgOut
- clientIPCListener :: ProtocolDuration -> ClientHandles -> Port -> IO (Either NodeIPCError ())
- testStartNodeIPC :: ToJSON msg => Port -> msg -> IO (MsgOut, MsgOut)
- data ServerHandles = ServerHandles {}
- data ClientHandles = ClientHandles {}
- closeFullDuplexAnonPipesHandles :: (ServerHandles, ClientHandles) -> IO ()
- createFullDuplexAnonPipesHandles :: IO (ServerHandles, ClientHandles)
- bracketFullDuplexAnonPipesHandles :: ((ServerHandles, ClientHandles) -> IO ()) -> IO ()
- serverReadWrite :: ServerHandles -> MsgIn -> IO (Either NodeIPCError MsgOut)
- data NodeIPCError
- data MessageSendFailure
- data MessageException = DecodeFail ByteString
- sendMessage :: (MonadIO m, ToJSON msg) => WriteHandle -> msg -> m ()
- readMessage :: (MonadIO m, MonadThrow m, FromJSON msg) => ReadHandle -> m msg
- exampleWithFD :: MsgIn -> IO (MsgOut, MsgOut)
- exampleServerWithProcess :: MsgIn -> IO (Either NodeIPCError (MsgOut, MsgOut))
- getReadWriteHandles :: IO (ReadHandle, WriteHandle)
- getHandleFromEnv :: String -> IO (Either NodeIPCError Handle)
- isIPCError :: NodeIPCError -> Bool
- isHandleClosed :: NodeIPCError -> Bool
- isUnreadableHandle :: NodeIPCError -> Bool
- isUnwritableHandle :: NodeIPCError -> Bool
- isNodeChannelCannotBeFound :: NodeIPCError -> Bool
Data types
Port that is used to communicate between Cardano-node and Daedalus
(e.g 8090
)
Message from the server being sent to the client.
Constructors
QueryPort | Ask which port to use |
Ping | Ping |
Shutdown | Shutdown message from the server |
MessageInFailure MessageSendFailure |
Instances
Eq MsgIn Source # | |
Show MsgIn Source # | |
Generic MsgIn Source # | |
Arbitrary MsgIn Source # | |
ToJSON MsgIn Source # | |
FromJSON MsgIn Source # | |
type Rep MsgIn Source # | |
Defined in Cardano.Shell.NodeIPC.Lib type Rep MsgIn = D1 ('MetaData "MsgIn" "Cardano.Shell.NodeIPC.Lib" "cardano-shell-0.1.0.0-31Sro4CeSAWE4uOGxln0rB" 'False) ((C1 ('MetaCons "QueryPort" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "Ping" 'PrefixI 'False) (U1 :: Type -> Type)) :+: (C1 ('MetaCons "Shutdown" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "MessageInFailure" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 MessageSendFailure)))) |
Message which is send out from Cardano-node
Constructors
Started | Notify Daedalus that the node has started |
ReplyPort Word16 | Reply of QueryPort |
Pong | Reply of Ping |
ShutdownInitiated | Reply of shutdown |
MessageOutFailure MessageSendFailure |
Instances
Eq MsgOut Source # | |
Show MsgOut Source # | |
Generic MsgOut Source # | |
Arbitrary MsgOut Source # | |
ToJSON MsgOut Source # | |
FromJSON MsgOut Source # | |
type Rep MsgOut Source # | |
Defined in Cardano.Shell.NodeIPC.Lib type Rep MsgOut = D1 ('MetaData "MsgOut" "Cardano.Shell.NodeIPC.Lib" "cardano-shell-0.1.0.0-31Sro4CeSAWE4uOGxln0rB" 'False) ((C1 ('MetaCons "Started" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "ReplyPort" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Word16))) :+: (C1 ('MetaCons "Pong" 'PrefixI 'False) (U1 :: Type -> Type) :+: (C1 ('MetaCons "ShutdownInitiated" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "MessageOutFailure" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 MessageSendFailure))))) |
IPC protocol
data ProtocolDuration Source #
When using pipes, the write doesn't block, but the read blocks! As a consequence, we eiter need to use IDs to keep track of the client/server pair, or (read) block so we know which message pair arrived. This might seems an overkill for this task, but it's actually required if we want to reason about it and test it properly.
>>>
(readEnd, writeEnd) <- createPipe
>>>
replicateM 100 $ sendMessage (WriteHandle writeEnd) Cardano.Shell.NodeIPC.Ping
[(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),()]
>>>
mesg <- replicateM 100 ((readMessage (ReadHandle readEnd)) :: IO MsgIn)
>>>
mesg <- (readMessage (ReadHandle readEnd)) :: IO MsgIn
Blocked!
The way the IPC protocol works - it either responds to a single IPC message or it remains in a loop responding to multiple messages.
Constructors
SingleMessage | Responds to a single message and exits |
MultiMessage | Runs forever responding to messages |
Instances
Eq ProtocolDuration Source # | |
Defined in Cardano.Shell.NodeIPC.Lib Methods (==) :: ProtocolDuration -> ProtocolDuration -> Bool # (/=) :: ProtocolDuration -> ProtocolDuration -> Bool # | |
Show ProtocolDuration Source # | |
Defined in Cardano.Shell.NodeIPC.Lib Methods showsPrec :: Int -> ProtocolDuration -> ShowS # show :: ProtocolDuration -> String # showList :: [ProtocolDuration] -> ShowS # |
startNodeJsIPC :: ProtocolDuration -> Port -> IO (Either NodeIPCError ()) Source #
Start IPC with NodeJS
This only works if NodeJS spawns the Haskell executable as child process
(See server.js
as an example)
startIPC :: ProtocolDuration -> ReadHandle -> WriteHandle -> Port -> IO (Either NodeIPCError ()) Source #
Start IPC with given ReadHandle
, WriteHandle
and Port
Arguments
:: ProtocolDuration | |
-> ClientHandles | |
-> Port | This is really making things confusing. A Port is here, but it's determined on the client side, not before. |
-> IO (Either NodeIPCError ()) |
Client side IPC protocol.
data ServerHandles Source #
The set of handles for the server, the halves of one pipe.
Constructors
ServerHandles | |
Fields |
data ClientHandles Source #
The set of handles for the client, the halves of one pipe.
Constructors
ClientHandles | |
Fields |
closeFullDuplexAnonPipesHandles :: (ServerHandles, ClientHandles) -> IO () Source #
Close the pipe handles.
createFullDuplexAnonPipesHandles :: IO (ServerHandles, ClientHandles) Source #
Creation of a two-way communication between the server and the client. Full-duplex (two-way) communication normally requires two anonymous pipes. TODO(KS): Bracket this!
bracketFullDuplexAnonPipesHandles :: ((ServerHandles, ClientHandles) -> IO ()) -> IO () Source #
A bracket function that can be useful.
serverReadWrite :: ServerHandles -> MsgIn -> IO (Either NodeIPCError MsgOut) Source #
This is a blocking call that sends the message to the client and returns it's response, after the client response arrives.
Exceptions
data NodeIPCError Source #
Exception thrown from Node IPC protocol
Constructors
NodeChannelNotFound Text | Node channel was not found |
UnableToParseNodeChannel Text | Unable to parse given |
IPCError | Exception thrown when there's something wrong with IPC |
HandleClosed Handle | Given handle is closed therefore cannot be used |
HandleEOF Handle | Given handle End Of File |
UnreadableHandle Handle | Given handle cannot be used to read |
UnwritableHandle Handle | Given handle cannot be used to write |
NoStdIn |
Instances
Eq NodeIPCError Source # | |
Defined in Cardano.Shell.NodeIPC.Lib | |
Show NodeIPCError Source # | |
Defined in Cardano.Shell.NodeIPC.Lib Methods showsPrec :: Int -> NodeIPCError -> ShowS # show :: NodeIPCError -> String # showList :: [NodeIPCError] -> ShowS # |
data MessageSendFailure Source #
Message that can be used to let the other know the that exception had occured
Constructors
ParseError Text | |
GeneralFailure |
Instances
data MessageException Source #
Exception
Constructors
DecodeFail ByteString |
Instances
Show MessageException Source # | |
Defined in Cardano.Shell.NodeIPC.Message Methods showsPrec :: Int -> MessageException -> ShowS # show :: MessageException -> String # showList :: [MessageException] -> ShowS # | |
Exception MessageException Source # | |
Defined in Cardano.Shell.NodeIPC.Message Methods toException :: MessageException -> SomeException # |
Used for testing
sendMessage :: (MonadIO m, ToJSON msg) => WriteHandle -> msg -> m () Source #
Send JSON message with given WriteHandle
readMessage :: (MonadIO m, MonadThrow m, FromJSON msg) => ReadHandle -> m msg Source #
Read JSON message with given ReadHandle
exampleServerWithProcess :: MsgIn -> IO (Either NodeIPCError (MsgOut, MsgOut)) Source #
Example of an IPC server that is using haskell executable as an server.
This will be the server, the one which sends the message (such as Ping
, QueryPort
)
to get the response from the client.
The client is executed via stack exec node-ipc haskell
getReadWriteHandles :: IO (ReadHandle, WriteHandle) Source #
Create a pipe for interprocess communication and return a
(ReadHandle
, WriteHandle
) Handle pair.
getHandleFromEnv :: String -> IO (Either NodeIPCError Handle) Source #
Acquire a Handle that can be used for IPC from Environment
Predicates
isIPCError :: NodeIPCError -> Bool Source #
Checks if given NodeIPCError
is IPCError
isHandleClosed :: NodeIPCError -> Bool Source #
Checks if given NodeIPCError
is HandleClosed
isUnreadableHandle :: NodeIPCError -> Bool Source #
Checks if given NodeIPCError
is UnreadableHandle
isUnwritableHandle :: NodeIPCError -> Bool Source #
Checks if given NodeIPCError
is UnwritableHandle
isNodeChannelCannotBeFound :: NodeIPCError -> Bool Source #
Checks if given NodeIPCError
is NodeChannelNotFound