Closed JonathanWilbur closed 1 year ago
Very briefly: LDAP is multiplexed by message ID, so the order of responses can be different than that of requests. I can go into more detail sometime next week if you wish.
I understand that. I actually implemented my own X.500/LDAP server. But I implemented it in TypeScript. My question is about whether this library exemplifies the "correct" way to handle a protocol (not just LDAP) that has an asynchronous request-response pattern where responses could be returned in a different order from their corresponding requests in Rust.
Serves me right for trying to compress a paragraph to a sentence in a hurry. Yes, of course you'd understand that LDAP is multiplexed. What I meant to say is, since LDAP is multiplexed, this library has to, and does, handle multiplexed operation.
The core machinery is in async fn turn
in src/conn.rs
. It manages a TCP connection to the server and a number of communication channels to the client handles. There is a connection-wide map of message IDs to oneshot data channels, which is how server responses are communicated back to clients.
I won't presume that this is the way to structure this kind of application, or that it can cleanly map to X.880 remote ops or similar. But it has worked well for LDAP, and has proved extensible without major restructuring.
My question is about whether this library exemplifies the "correct" way to handle a protocol (not just LDAP) that has an asynchronous request-response pattern where responses could be returned in a different order from their corresponding requests in Rust.
I'd like to add a bit of context to that: First off, keep in mind that when this crate was initially written tokio did not exist yet and async/await was the thing C# did and a far-off dream for Rust. Ivan forked off rust-ldap (and, for the record, has done a terrific job making this crate so much more than I would have ever had the time to) back when tokio starting being a thing and he wanted to make use of it. Back then tokio-proto
was the new kid on the block regarding multiplexed protocols like LDAP, and you can see it in some of the design decisions.
So, yes I would say this crate is a good example of how to handle multiplexed protocols, but it was started some 7-ish years ago, and the Rust ecosystem has changed drastically over those 7 years. If I had to write a library like this today, it would probably look different.
std::future
exists and being compatible to that is quite a benefit.tower
exists as the evolution of what tokio-proto
and tokio-service
wanted to be but never really were. That alone would probably make a modern take look very different just by itself.bytes
. The general architecture of a multiplexed protocol works really well with how bytes
implements zero-copy, and making even more use of that on even deeper levels would influence crate design to the better.Thank you both so much for your thoughtful answers! I will put your wisdom to great use. Thanks again!
Hello! I am a little new to Rust, but I've been programming for a long time in other languages. I get most of Rust, but how to do async programming well does not seem clear to me. I am trying to implement an X.500 client library (as in DAP instead of LDAP), so it uses similar request-response behavior to LDAP. In particular, responses may be received in a different order than their corresponding requests, and I am figuring out how to handle this in async Rust.
To get to the point: would you say this library is exemplary of a correct way to handle async request-response protocols?
Thanks in advance!