Skip to content

Finish NetworkActor #7

Description

@efimio16

This will be a parent issue for smaller ones.

When it's finished, it should look something like that:

// ping-pong/query.rs

const SERVICE_ID: u16 = 1;

// Query
#[derive(Clone, Serialize, Deserialize)]
struct Ping {
    some_useful_data: i64
}

// Reply
#[derive(Clone, Serialize, Deserialize)]
struct Pong {
    satisfied: bool
}

impl Replyable for Pong {
    // Verifies raw query to change local peer score. Defaults to `None`
    fn verify(&self, _: &Query) -> VerificationMethod {
        VerificationMethod::None
    }
}

impl Queryable for Ping {
    // These constants allows communication between peers even if one of them doesn't know all queries that knows another peer.
    const SERVICE_ID: u16 = SERVICE_ID;
    const METHOD_ID: u16 = 1;
    // Reply type
    type Reply = Pong;

    // To whom is this query addressed
    fn peer_selection(&self) -> PeerSelection {
        PeerSelection::Random(5)
    }
    
    // To prevent abuse, what kind of PoW (Proof-of-Work) challenge should a node return. Defaults to `None`
    fn pow_config(&self) -> PowConfig {
        PowConfig::Low
    }
}

// ping-pong/service.rs

struct PingPongService {
    network_rx: mpsc::Receiver<Query>, // Receive queries
    network_handle: NetworkHandle,     // and answer to them
}

#[actor]
impl PingPongService {
    pub fn new(network_rx: mpsc::Receiver<Query>, network_handle: NetworkHandle) -> Self {
        Self { network_rx, network_handle }
    }

    #[listen(self.network_rx.recv())]
    async fn query(&mut self, q: Query) {
        match q.method_id {
            Ping::METHOD_ID => {
                let ping: Ping = q.into(); // Deserializes from bytes
                let pong = Pong { satisfied: ping.some_useful_data > 0 };

                // query_id links this reply to the ping query
                pong.reply_to(q.query_id, &self.network_handle).await;
            }
            _ => {} // unknown
    }
}

// node/main.rs

fn main() {
    let (pingpong_net_tx, pingpong_net_rx) = Channel::new(1024);
    let network_handle = NetworkActor::new()
        .register(ping_pong::SERVICE_ID, pingpong_net_tx)
        .spawn();

    PingPong::new(pingpong_net_rx, network_handle).spawn();
}

// client/main.rs

fn main() {
    let network = NetworkActor::new().spawn();
    let Pong { satisfied } = Ping { some_useful_data: -1 }.query(&network).await.expect("something went wrong");
    assert!(!satisfied);
}

The API design isn't final yet, so if you have any ideas, I'd love to hear them!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions