diff --git a/src/node/protocol/membership.rs b/src/node/protocol/membership.rs new file mode 100644 index 0000000..64338c3 --- /dev/null +++ b/src/node/protocol/membership.rs @@ -0,0 +1,110 @@ +// Copyright 2024 Kulpreet Singh + +// This file is part of Frost-Federation + +// Frost-Federation is free software: you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. + +// Frost-Federation is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Frost-Federation. If not, see +// . + +use crate::node::protocol::Message; +use futures::{Future, FutureExt}; +use serde::{Deserialize, Serialize}; +use std::pin::Pin; +use std::task::{Context, Poll}; +use tower::{BoxError, Service}; + +#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, Default)] +pub struct MembershipMessage { + pub sender_id: String, + pub message: Vec, +} + +impl MembershipMessage { + pub fn new(sender_id: String, members: Vec) -> Self { + MembershipMessage { + sender_id, + message: members, + } + } +} + +#[derive(Debug, Clone, Default)] +pub struct Membership { + sender_id: String, +} + +impl Membership { + pub fn new(node_id: String) -> Self { + Membership { sender_id: node_id } + } +} + +/// Service for handling Membership protocol. +impl Service for Membership { + type Response = Option; + type Error = BoxError; + type Future = Pin, Self::Error>> + Send>>; + + fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll> { + Poll::Ready(Ok(())) + } + + /// Membership doesn't respond with anything. It is pushed by a + /// node when anyone connects to it. + fn call(&mut self, _msg: Message) -> Self::Future { + async move { Ok(None) }.boxed() + } +} + +#[cfg(test)] +mod membership_tests { + + use super::Membership; + use crate::node::protocol::MembershipMessage; + use tower::{Service, ServiceExt}; + + #[tokio::test] + async fn it_should_create_membership_as_service_and_respond_to_none_with_membership() { + let mut p = Membership::new("local".to_string()); + let res = p + .ready() + .await + .unwrap() + .call(MembershipMessage::default().into()) + .await + .unwrap(); + assert!(res.is_none()); + // assert_eq!( + // res, + // Some(MembershipMessage::new("local".to_string(), vec!["a".to_string()]).into()) + // ); + } + + #[tokio::test] + async fn it_should_create_membership_as_service_and_respond_to_membership_with_none() { + let mut p = Membership::new("local".to_string()); + let res = p + .ready() + .await + .unwrap() + .call(MembershipMessage::new("local".to_string(), vec!["a".to_string()]).into()) + .await + .unwrap(); + assert!(res.is_none()); + } + + #[test] + fn it_should_create_default_membership_message() { + assert_eq!(MembershipMessage::default().sender_id, "".to_string()) + } +}