-
Notifications
You must be signed in to change notification settings - Fork 213
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adapt NodeIPC module from cardano-sl #388
Adapt NodeIPC module from cardano-sl #388
Conversation
~~@rvl I am afraid you've done some double-work done on this PR :s ... ~~
Nevermind, just saw your comment on your development plan:
|
6e79d65
to
5cdcab3
Compare
9695881
to
f7e12ed
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM overall, but haven't really got time to play with it.
Also, some modification regarding ports have already been included in #407
@@ -76,6 +78,7 @@ library | |||
Cardano.Wallet.Api | |||
Cardano.Wallet.Api.Server | |||
Cardano.Wallet.Api.Types | |||
Cardano.Wallet.DaedalusIPC |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a big fan of referring to Daedalus
here. The IPC stuff can be seen as a low-level protocol to allow a client to perform some process management task of the wallet server. Of course, the primary user is Daedalus, but I don't want us to fall in the trap of "making stuff just for the frontend" as a Daedalus***
module would suggest. This already caused us quite some pain with the old API that has some non-sensical stuff into it.
In short: let's build more generic interfaces that serve a well-defined purpose.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that NodeIPC
was rather confusing, so maybe have something like NodeJSIPC
or JSClientIPC
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One of our main requirements is working with the Daedalus frontend. This ipc protocol is unique to Daedalus. I'm not aware of any requirements for integrating with some imaginary software that doesn't exist yet, but we can change the name if that happens.
It would be better to document the ways of starting cardano-wallet server on a port, so that prospective users can assess whether any of the schemes would work for them.
sayErr "[INFO] Daedalus IPC is not enabled" | ||
sleep | ||
Left (NodeChannelBadFD err) -> | ||
sayErr $ "[ERROR] Starting Daedalus IPC: " <> err |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now that we've the logging infrastructure setup, I'd suggest to switch to using the trace object instead of any other outputting method 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK
}); | ||
} | ||
}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be worth adding a negative test case with Daedalus sending some gibberish at first, to see that the ParseFailure
message gets triggered correctly 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a test. You might have noticed the tests are a bit thin. That's because
- cardano-shell has more tests, and we will probably move the code there
- I think it's worth considering inheriting the socket from the parent process, rather than implementing some hokey message protocol.
-- run launcher in the tests. But that dependency can't be expressed in the | ||
-- cabal file, because otherwise there would be a cycle. | ||
-- | ||
-- So one hacky way to work around it is by running programs under "stack exec". |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
-> IO () | ||
ipcListener handle onMsg chan = do | ||
hSetNewlineMode handle noNewlineTranslation | ||
catch (race_ replyLoop sendLoop) onIOError |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice pattern. I'd have a slight preference for concurrently
instead of race_
since we aren't actually expecting any of the two sides to eventually terminate (which race_
conveys). We still get the cancellation behavior with concurrently
if I am correct.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It really doesn't matter which one. Both of them imply the wrong thing. But if concurrently
makes you happy, then I'll change it.
onIOError :: IOError -> IO () | ||
onIOError err = do | ||
sayErrString $ "[ERROR] Exception caught in DaedalusIPC: " <> show err | ||
when (isEOFError err) $ sayErr "[DEBUG] it's an eof" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An EOF
here would mean that Daedalus / the client has closed the connection on their hand, right ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Usually the exception is usually broken pipe. I think this was debug code that got left in cardano-sl from the DEVOPS-1234 investigation. I have removed the log anyway.
act | ||
Left NodeChannelDisabled -> do | ||
sayErr "[INFO] Daedalus IPC is not enabled" | ||
sleep |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why sleeping here? What would be the consequence of returning ()
? Do we expect daedalusIPC
to never return? If so, I'd rather have it mentioned in a function comment to explain this behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it should have been commented. This is the error handling I want:
- If set up is unsuccessful, return immediately, causing the cardano-wallet process to exit. Daedalus does not want zombie cardano-wallet processes hanging around that it can't communicate with.
- If set up is successful, never return until Daedalus exits.
- If not running within a nodejs channel, never return (simplifies calling code)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, so we really assume that any termination is an error, hence the sleep when there's no node.js channel (not an error so to speak).
exe/wallet/Main.hs
Outdated
Server.start logStartup walletPort wallet | ||
Server.withListeningSocket walletPort $ \(port, socket) -> do | ||
let settings = Server.mkWarpSettings logStartup port | ||
race_ (daedalusIPC port) (Server.startOnSocket settings socket wallet) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah! I supposed this is why we make the daedalusIPC
hangs forever. I believe that switching for concurrently
instead of race_
would remove that limitation since the action could return without cancelling the startOnSocket
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to be race
so that the program exits when there is an error from daedalusIPC
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got you, this comment of yours clarifies the choice of race
indeed. I'd suggest to have the behavior documented either on the call-site or, somewhere in the DaedalusIPC. Maybe in both places.
edit: I see it's now the case
e6cf806
to
3d63b7b
Compare
This takes the cardano-sl/cardano-shell NodeIPC code and splits the general nodejs child_process IPC protocol out from the Daedalus/Cardano specific protocol, improves the exception handling, changes the logging, and just makes it simpler.
Removing a type constructor can change the shape of the JSON.
3d63b7b
to
5413101
Compare
Merging into #414 to group PRs and avoid multiple merges because of CI issues due to stack major bump today .... |
Relates to issue #144
Overview
QueryPort
, waiting forReplyPort
, as Daedalus does.--state-dir
in the same Spec.