rust-amqp
rust-amqp copied to clipboard
`try_clone` "does not behave as expected and will be removed in a future release"
Greetings. We use rust-amqp
heavily at work, in production. Thank you for implementing it!
rust-amqp
relies on try_clone
, which is missing in newer versions of OpenSSL (and in portability libraries like native-tls
). But even in older versions of OpenSSL, try_clone
comes with a pretty serious warning:
Deprecated
This method does not behave as expected and will be removed in a future release.
According to a discussion at sfackler/rust-native-tls#89:
It is not possible to implement try_clone on any backend. A TLS stream is inherently stateful.
Since we have no choice but to use TLS at work, we need to address this issue for our own projects.
We actually have a partial port of rust-amqp
to native-tls
, but it's buggy because of the unresolved try_clone
issue, so we've never submitted a PR for it.
We would be happy to contribute significant labor to updating rust-amqp
. Do you have any ideas on the best way to proceed? We've roughed out a couple of ideas ourselves, including the possibility of converting rust-amqp
to a single-threaded library and using one Session
per thread. We've also thought about switching over to async, but we haven't thought through the issues yet. (And while addressing these issues, we'd really like to add/merge heartbeat support.)
Thank you for your advice and for your library!
OK, I took a look at several other AMQP libraries, and consulted with my co-workers, and we decided that the easiest fix would be to reimplement the core socket code using tokio
and tokio_openssl
. This would allow us to implement full-duplex TLS connections and fix the event loop to no longer need try_clone
.
I'm currently working on some proof-of-concept code here. Over the next couple of days, I hope to turn this into a demonstration of a full-duplex TLS client.
OK, I've implemented a Tokio-based Connection
class with a synchronous interface designed to mimic amqp::Connection
. Here are the interesting bits of code:
-
The client and server. The
client
function is the interesting bit. -
The
Connection
class. This usestype Frame = String
andLineCodec
for simplicity, but the basic structure is all there. Note thatconnection.split()
will return(ReadConnection, WriteConnection)
, giving you two halves that you can use independently. TheWriteConnection
is cloneable.
This needs an AmqpFrameCodec
to replace LineCodec
, as well as some code to handle frame splitting, and the error and shutdown conditions could be made much more graceful. But I think it demonstrates that the basic strategy really ought to work.