0

I'm very new to Rust and willing to make some Linux service for Orange Pi Zero in Actix-web, that will act as a "gateway" to other network device (some dumb Chinese network relay with 4 inputs and 4 ouputs which is controlled by AT commands via TCP or UDP) and will asynchronously poll that device and convert its output as a constantly refreshed web page via WebSocket. I want to make 2 different actors, the first one should be a TCP client actor that polls a relay via run_interval(), makes a network request with appropriate AT command, reads a response and sends a message to WebSocket actor that will push messages with input states to web page. I successfully implemented the WebSocket one and trying to implement another actor using TcpStream, FramedWrite and LinesCodec. My TCP actor looks like this:

struct TcpClientActor {
    framed: actix::io::FramedWrite<
        String,
        WriteHalf<TcpStream>,
        LinesCodec,
    >,
}

I also have a bunch of another trait implementations for it, that are compiled without any issues, but stuck on struct itself, the compiler complains with the following error:

the trait `tokio::io::async_write::AsyncWrite` is not implemented for `tokio::io::split::WriteHalf<tokio::net::tcp::stream::TcpStream>`

I checked the Actix sources and found that AsyncWrite is already implemented for WriteHalf, as well as for TcpStream, but can't get it compiled without errors.

This is my [dependencies] section of Cargo.toml:

[dependencies]
# sysfs_gpio = "0.5"
actix = "0.10"
actix-codec = "0.3"
actix-web = "3"
actix-web-actors = "3"
actix-files = "0.3"
env_logger = "0.7"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
json = "0.12"
#mio = "0.7"
tokio = { version = "0.3.1", features = ["full", "tracing"] }
tokio-util = "0.3.1"

Additionally, I want to wrap the first actor with Supervisor to handle the disconnects and other network issues. Please provide any examples.

Will appreciate any help.

Skyggedans
  • 25
  • 5

1 Answers1

1

You have probably hit an unfortunately confusing case of conflicting dependencies.

The actix crate has a dependency on tokio 0.2.6. However, you've listed your dependency as tokio 0.3.1. Cargo considers 0.2.x and 0.3.x to be incompatible and will therefore include two versions of tokio in your project. The cause of the confusing error message is you're using a 0.3 version of WriteHalf but the actix FramedWrite is execting something implementing the 0.2 version of AsyncWrite.

The fix is probably to downgrade your version of tokio to 0.2

See also: Why is a trait not implemented for a type that clearly has it implemented?

kmdreko
  • 42,554
  • 6
  • 57
  • 106
  • Thanks for your answer. Yes, I suspected that and tried to downgrade tokio already, but in that case I'm facing a lot of another compilation errors. – Skyggedans Oct 26 '20 at 08:55
  • I can't help you without more concrete information. If the downgrade fixed *this particular issue* then I've answered your question as posted. I can't predict if the fix would cause more issues because *I can't see your code*. I suggest you post a new question *with your code* so that you can get a better solution. – kmdreko Oct 26 '20 at 12:42
  • There were [a number of changes](https://tokio.rs/blog/2020-10-tokio-0-3) between 0.2 and 0.3 that may need to be addressed with the downgrade. – kmdreko Oct 26 '20 at 13:16
  • Ok, the error is gone after downgrade, now I have this one while trying to attach a stream: `ctx.add_stream(FramedRead::new(r, LinesCodec::new()));` The error: `type mismatch resolving , tokio_util::codec::lines_codec::LinesCodec> as futures_core::stream::Stream>::Item == std::string::String` – Skyggedans Oct 26 '20 at 13:26
  • I think [`FramedRead as Stream`](https://docs.rs/tokio-util/0.3.1/tokio_util/codec/struct.FramedRead.html#impl-Stream) has `Item` as `Result` not just `String`, I don't know where that constraint is coming from – kmdreko Oct 26 '20 at 13:49
  • Ok, seems to be fixed. Now I have another issue - the device on other end only supports execution of commands one by one, so to poll all 4 inputs I have to send 4 separate packets in a loop with some delay between them, but FramedWrite.write() packs all the commands into one packet and the device returns an error. How can I "flush" a writer somehow (as a regular TcpStream allows to do) to accomplish that? Can't find any appropriate methods. – Skyggedans Oct 26 '20 at 22:34
  • You should post a new question – kmdreko Oct 26 '20 at 23:35