1tgr / rust-websocket-lite

A fast, low-overhead WebSocket client
MIT License
115 stars 17 forks source link

Updating tokio-util dependency in minor version broke semver #300

Closed Xiretza closed 1 year ago

Xiretza commented 2 years ago

270 updated the externally visible tokio-util dependency across a semver-incompatible boundary (0.6 to 0.7), and the affected crates were subsequently released without incrementing the major version. This breaks crates depending on them, e.g.:

$ cargo new foo
$ cd foo
$ echo -e 'hyper-websocket-lite = "0.5.0"\ntokio = {version = "1", features = ["rt"]}' >> Cargo.toml
$ cargo build
[...]
error[E0599]: no method named `framed` found for struct `MessageCodec` in the current scope
   --> /home/xiretza/.cargo/registry/src/github.com-1ecc6299db9ec823/hyper-websocket-lite-0.5.0/src/lib.rs:41:53
    |
41  |                 let client = MessageCodec::server().framed(upgraded);
    |                                                     ^^^^^^ method not found in `MessageCodec`
    |
   ::: /home/xiretza/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-util-0.7.3/src/codec/decoder.rs:178:8
    |
178 |     fn framed<T: AsyncRead + AsyncWrite + Sized>(self, io: T) -> Framed<T, Self>
    |        ------ the method is available for `MessageCodec` here
    |
    = help: items from traits can only be used if the trait is in scope
help: the following trait is implemented but not in scope; perhaps add a `use` for it:
    |
6   | use tokio_util::codec::decoder::Decoder;
    |

This is because hyper-websocket-lite 0.5.0 depends both on tokio-util 0.6 and websocket-codec, but the latest compatible websocket-codec version (0.5.2) now pulls in tokio-util 0.7 (due to the >= 0.6 constraint). Thus, hyper-websocket-lite's tokio_util::codec::decoder::Decoder (from tokio-util 0.6) is different from websocket-codec's tokio_util::codec::decoder::Decoder (from tokio-util 0.7).

The proper solution here is to yank all affected versions (i.e. websocket-codec and websocket-lite versions 0.5.1 and 0.5.2), republish the crates under a new major version, and avoid >= dependencies like the plague - they undermine the whole purpose of semver, since there's no way for you to actually guarantee that you will remain compatible with any breaking changes of the dependency.

1tgr commented 2 years ago

Thanks for reporting this, I'll take a look and sort it out

1tgr commented 2 years ago

In the foo repro above I don't see why cargo is choosing tokio-util 0.6 for websocket-codec and 0.7 for hyper-websocket-lite, but from reading https://doc.rust-lang.org/cargo/reference/resolver.html it looks like it's allowed to behave this way. (In the Cargo.lock in rust-websocket-lite itself, both get resolved to 0.7.)

It looks like my attempt in #270 to depend on either tokio-util 0.6 or 0.7 is not helpful and we should just have a semver bump of the crates in this repo. At this point there probably isn't a strong reason to still support tokio-util 0.6.