| 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