use crate::GspSignal;
use gbp::CodecError;
use gbp_core::{GbpFlags, MemberId, SignalType, StreamType};
use gbp_node::{GroupNode, NodeError, OutboundFrame, Sealer};
use std::collections::HashSet;
#[derive(Debug, thiserror::Error)]
pub enum GspError {
#[error("decode: {0}")]
Decode(#[from] CodecError),
#[error("unknown signal_type: {0}")]
UnknownSignal(u32),
#[error("duplicate request_id: {0}")]
DuplicateRequest(u32),
#[error("node: {0}")]
Node(#[from] NodeError),
}
#[derive(Debug, Clone)]
pub struct GspAccept {
pub signal: SignalType,
pub sender_id: MemberId,
pub role_claim: u32,
pub request_id: u32,
}
#[derive(Default)]
pub struct GspClient {
seen_requests: HashSet<u32>,
pub muted: HashSet<MemberId>,
pub members: HashSet<MemberId>,
}
impl GspClient {
pub fn new() -> Self {
Self::default()
}
pub fn send<S: Sealer>(
&mut self,
node: &mut GroupNode,
seal: &mut S,
target: MemberId,
signal: SignalType,
role_claim: u32,
request_id: u32,
) -> Result<OutboundFrame, GspError> {
let mut sig = GspSignal::bare(signal as u32, request_id, node.member_id);
sig.role_claim = role_claim;
let stream_id = node.member_stream_id(3);
Ok(node.send_payload(
seal,
target,
StreamType::Signal,
stream_id,
GbpFlags::ordered_reliable_ack(),
&sig.to_cbor(),
)?)
}
pub fn accept(&mut self, plaintext: &[u8]) -> Result<GspAccept, GspError> {
let s = GspSignal::from_cbor(plaintext)?;
let signal = SignalType::try_from(s.signal_type).map_err(GspError::UnknownSignal)?;
if !self.seen_requests.insert(s.request_id) {
return Err(GspError::DuplicateRequest(s.request_id));
}
match signal {
SignalType::Join => {
self.members.insert(s.sender_id);
}
SignalType::Leave => {
self.members.remove(&s.sender_id);
self.muted.remove(&s.sender_id);
}
SignalType::Mute => {
self.muted.insert(s.sender_id);
}
SignalType::Unmute => {
self.muted.remove(&s.sender_id);
}
_ => {}
}
Ok(GspAccept {
signal,
sender_id: s.sender_id,
role_claim: s.role_claim,
request_id: s.request_id,
})
}
pub fn reset(&mut self) {
self.seen_requests.clear();
}
}