-
Notifications
You must be signed in to change notification settings - Fork 74
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
Conduit 3 API feedback/questions #339
Comments
Yes indeed (in the lwt-unix case at least). Based on @emillon work we now have https://github.com/mirage/ca-certs (no support for windows yet, though) that reads the default trust anchors on your Unix system (Linux/BSD/macOS) and uses the current time for certificate validation. If you run into trouble with the ca-certs package, please report an issue, and we'll make sure that it works on your favourite Linux distribution. (PRs for (a) windows support and (b) macOS via system API instead of calling the For MirageOS (i.e. no host system trust anchors), a similar library https://github.com/mirage/ca-certs-nss is available which imports the trust anchors from Firefox / Netscape Security Services. I announced these packages at https://discuss.ocaml.org/t/ann-ca-certs-and-ca-certs-nss/6804 |
Hi, thanks for this huge feedback 👍, I will try to explains all of these points and explain possible solutions
I think you point the biggest problem about the new API of Conduit. At this level, I was thinking about a possible abstract way to handle any protocols. For me, the idea of a So I took the most common and required information which can be used by any protocols. A domain-name (and therefor an IP) seems, for me, a well unique identifier to recognize, from others, an endpoint. Others information, such as the port, are a complement of I think this assumption seems unusual for most of real cases but it fits well for a MirageOS (in my view) which can use some others protocols than TCP/IP. I tried to explain that here but a more clear explanation is: we should separate what comes from a context and what we strictly need. By this way, a
See
My idea is to make an extra library (which can be in the Conduit distribution) to handle the I think we missed several extra cases (such as Git) and focus on only what CoHTTP expects - then, we tried to enforce as much as we can others protocols like Git/Websocket/VCHAN to this layout without something homogeneous and consistent. Conduit 3.0 breaks all of these things and even if we can say that we have some kind of regressions about usability (and factually it's true), I think we provide a more interesting way which unlocked several possibilities (such as the possibility to use your own From my experiments with type something
val endpoint_and_resolvers_from_something : something -> (Conduit.Endpoint.t * Conduit.resolvers)
let connect : ?resolvers:Conduit.resolvers -> something -> result = fun ?(resolvers= Conduit.empty) something ->
let edn, resolvers' = endpoint_and_resolvers_from_something something in
let resolvers = Conduit.merge (* like Map.merge to keep user-defined resolvers *) resolvers resolvers in
Conduit.resolve ~resolvers edn >>? fun flow ->
Yes, you are completely true and we should rework on the tutorial - I was thinking that it was not on my responsibility (as Conduit) to provide
This reason is a bit complex (and should discuss about that in an other issue) but it's currently hard to fix the semantic of ocaml-conduit/src/mirage/conduit_mirage_flow.mli Lines 1 to 11 in 1ebbd61
So you just highlight the most strangest type trick of Conduit 🎉 ! So you are right that we should remove it from the API - however, we really need it internally from some obscure reasons.
I agree with you that
For all of your points, I would like to say:
Then, you have the possibility to prove which implementation you use but we can not go further.
I think that we did not try to detail what does
It can not be by essence. I mean Conduit 2.0 shows to us the limit to try to homogenize any protocols into one and unique
The goal of Conduit 3.0 is to provide a generic way to choose the protocol implementation - which is a bit different to: a generic value to represent a protocol implementation.
You are true but several questions come then about "the way" to implement the main server loop:
A choice was made to be less magic about service - we don't have a dispatch (such as
Agree with that 👍.
It comes from a special request for Irmin: here
Not sure to understand what you mean.
I trust on you and if you can propose a PR about that, I will happy to review and merge it 👍 - note that this part is outside the core of Conduit (you should take a look on
I think, the question is more about the |
#358 fix this issue and does a single and unique
Again, #358 will fix this issue too. We will follow exactly what
Unfortunately, it seems that you require something more complex than
But the idea of Conduit 3 (despite Conduit 2) is the ability to extract the In that case, Conduit is not the solution because you don't want to be abstract over the protocol. An abstraction over the protocol implies, in any way, some limitations, whether by functor or by Conduit. Conduit is like an injection of a specific implementation to something else without functors. But it still is, in terms of OCaml, an other kind of a functor. So it's not magic and when you use Conduit, we need to accept the deal to restrict your use of your protocols to a simple and common signature (e.g. |
I've made some benchmarks of various APIs (mirage-flow, conduit 3, objects) here: https://github.com/talex5/flow-tests |
I was asked to try updating stuff to conduit 3 and report any questions/problems I have. I'll try to keep track of them here.
Endpoint
The
Endpoint
module seems very confusing. It defines an endpoint as a host name or an IP address, without a port number.There is no direct way to pass a port to
resolve
. The example at https://mirage.github.io/ocaml-conduit/conduit-lwt/Conduit_lwt/index.html#resolution defines anhttp_resolver
that always fixes port as 80.Looking in the cohttp code to see how a library could use this (https://github.com/mirage/ocaml-cohttp/blob/4b834d57ab24b94791be9b4b68e228a83139d85a/cohttp-lwt-unix/src/net.ml#L45) it seems that cohttp takes a list of resolvers from the user, looks at the URI, and then overrides the user's resolvers with its own ones that set the port to what the user requested! In particular, it overrides the user's TLS configuration settings while doing this!
On the plus side, from the code it looks like certificate checks now default to "on", which is a major improvement!
I suspect that users will either want to supply the configuration directly (using
connect
instead ofresolve
) or connect using a URI rather than a domain name. Perhaps the endpoint and resolver stuff should be moved to a separate library, to simplify the conduit API?Tutorial
I read the tutorial at https://mirage.github.io/ocaml-conduit/conduit/howto.html.
I found this a bit frustrating because it starts by assuming the existence of a conduit-aware
getline
function, which is never defined. Therefore it is not possible for the user to run the example.It says that
getline can be implemented as well with Conduit.S.recv
. However,Conduit_lwt.TCP
(the implementation the user is told to use) says:Therefore, it is not possible to use
recv
to input a line, unless you read the data one byte at a time.(and when I tried it, it returned that it had read
0
bytes of data for some reason)I think it would also help with the tutorial to start by giving the typical OO API from other languages, and then explain conduit's improvements over that. e.g. something like:
Otherwise, it's easy to get lost with all the open types, type witnesses, etc, before you even understand what conduit is trying to do.
Client-side conduits
Conduit.S.scheduler
definestype scheduler
as abstract (https://mirage.github.io/ocaml-conduit/conduit/Conduit/module-type-S/index.html#type-scheduler). This doesn't appear to be used anywhere else in the API. It can probably be removed.type error is defined as either
Msg
orNot_found
. It's not clear whatNot_found
means in this context. In particular,recv
,send
andclose
all say they can return this.It would be good to specify the behaviour of these functions more precisely. In particular:
recv
does a single read or tries to read its buffer (should be single IMHO, although TCP is perhaps not doing this at the moment).send
does (one call or many).mirage-flow
says "There is no indication when the buffer has actually been read and, therefore, it must not be reused". It would be good to clarify whether or not conduit has this restriction.close
saysSubsequent calls to recv will return Ok `End_of_flow
. How do I shut down just the sending side and then wait for the response?It's also not clear to me why these functions are defined as "client-side", since it seems they would be used server-side too.
What does
register ~protocol
do? Where is it registered?I got a bit lost with the protocols and services stuff. I guess this is so that I can pass e.g.
TCP
orTLS
to something and have it connect/accept by itself. But since it will have to provide the port and, for TLS, security information, it seems that this can't be quite generic.For a server socket, it seems like the code that chooses the protocol and service might as well just go ahead and create the listening socket with the appropriate configuration too.
The function
seems to boil down to "Give me an argument and a function and I'll call it for you".
Initial thoughts on updating stuff
prometheus-app
The diff is:
Conduit_lwt.TCP.configuration
. Then it could supply defaults forcapacity
and the bind address, and not break if we add new fields later.()
onServer.create
.create
ignores the backlog unless the service happens to beTCP
.I think it might be better if the listen/accept loop moved to conduit itself. e.g. something like:
Hmm, there is a
Conduit_lwt.serve
. But it returns aLwt_condition.t
to stop it. That's racy - if you broadcast on stop before the loop callswait
then it will miss the event! And it really shouldn't be callingwait
each time around the loop.The normal Lwt way to do that would be to take
Lwt_switch
argument and abort the loop when the switch is turned off.A switch can only be turned off once and so you can't miss the event. Also, the switch argument can be optional in the common case where you never want to stop.
mirage-capnp
This doesn't use conduit at the moment. It provides its own dynamic flow type over mirage-flow:
https://github.com/mirage/capnp-rpc/blob/53a38de36d02618eb87e99703f6338dbadcf5845/capnp-rpc-net/endpoint.ml#L10
Combined with capnproto/capnp-ocaml#71, the conduit API might make things more efficient by allowing us to read into a pre-existing buffer, avoiding a copy.
However, the current
recv
behaviour is no good - it needs to return as soon as it has some data, not wait for the buffer to be filled.0install
I was overriding a lot of stuff in cohttp/conduit to ensure that certificate authentication was configured correctly. I need to check the new system, but it looks like authentication is configured by default now, which is great!
The text was updated successfully, but these errors were encountered: