wenig / actix-telepathy

Cluster extension for actix
Apache License 2.0
69 stars 5 forks source link

One struct can't derive Message and RemoteMessage at the same time #78

Closed lucasmsoares96 closed 1 year ago

lucasmsoares96 commented 1 year ago
use actix::prelude::*;
use actix_broker::BrokerSubscribe;
use actix_telepathy::prelude::*;
use serde::{Serialize, Deserialize};
use std::net::SocketAddr;

#[derive(Message, RemoteMessage, Serialize, Deserialize)]
#[rtype(result = "()")]
struct MyMessage {
    pub(crate) source: RemoteAddr
}

#[derive(RemoteActor)]
#[remote_messages(MyMessage)]
struct MyActor {
    state: usize
}

impl Actor for MyActor {
    type Context = Context<Self>;

    fn started(&mut self, ctx: &mut Self::Context) {
        self.register(ctx.address().recipient());
        self.subscribe_system_async::<ClusterLog>(ctx);
    }
}

impl Handler<MyMessage> for MyActor {
    type Result = ();

    fn handle(&mut self, _msg: MyMessage, _ctx: &mut Self::Context) -> Self::Result {
        println!("RemoteMessage received!")
    }
}

impl Handler<ClusterLog> for MyActor {
    type Result = ();

    fn handle(&mut self, msg: ClusterLog, _ctx: &mut Self::Context) -> Self::Result {
        match msg {
            ClusterLog::NewMember(node) => {
                println!("New member joined the cluster.");
                let remote_addr = node.get_remote_addr(Self::ACTOR_ID.to_string());
                println!("{:?}", node.socket_addr);
                remote_addr.do_send(MyMessage {})
            },
            ClusterLog::MemberLeft(_ip_addr) => {
                println!("Member left the cluster.")
            }
        }
    }
}
impl ClusterListener for MyActor {}

#[actix::main]
pub async fn main(own_addr: SocketAddr, seed_nodes: Vec<SocketAddr>) {
    let _addr = MyActor { state: 0 }.start();
    let _cluster = Cluster::new(own_addr, seed_nodes);
    tokio::time::sleep(std::time::Duration::from_secs(20)).await;
}
➜  prototype git:(39367df) ✗ cargo build
   Compiling prototype v0.1.0 (/home/lucas/prototype)
error[E0119]: conflicting implementations of trait `actix::Message` for type `MyMessage`
 --> src/example.rs:7:19
  |
7 | #[derive(Message, RemoteMessage, Serialize, Deserialize)]
  |          -------  ^^^^^^^^^^^^^ conflicting implementation for `MyMessage`
  |          |
  |          first implementation here
  |
  = note: this error originates in the derive macro `RemoteMessage` (in Nightly builds, run with -Z macro-backtrace for more info)

For more information about this error, try `rustc --explain E0119`.
error: could not compile `prototype` (bin "prototype") due to previous error
wenig commented 1 year ago

Message gets automatically derived when deriving RemoteMessage. See this example: https://github.com/wenig/telepathy-examples/blob/main/paper-example/src/example.rs

wenig commented 1 year ago

Is this connected to #77 ? If so, we can close this issue and your examples should work now. Bear in mind, that you also do not need to specify the rtype for remote messages because they cannot receive a response (with .send()) so far.

lucasmsoares96 commented 1 year ago

I understood. In case I need a local message with response, do I need to create a different message?

wenig commented 1 year ago

Yes, you need to. Also, I would advise you to because otherwise you have different behavior for the same message. That can become an erroneous spot in your code. You could, as a suggestion, have a wrapper for the local message, which has the remote message as an attribute. That way, you only have to define it once.

#[derive(RemoteMessage, Serialize, Deserialize)]
struct MyMessage {
    ...
}

#[derive(Message)]
#[rtype(result = "()")]
struct MyLocalMessage(MyMessage)

Something like that!