prns-core 0.3.4

Pure Reticulum engine and wire contract for Personal Reticulum
use super::{accepted_reply, private, unexpected, SamExchange};
use crate::interfaces::i2p::sam::{
    I2pPrivateDestination, SamCommand, SamProtocolError, SamReply, SamReplyKind,
    SamSessionDestination, SamSessionId, SamSessionReplyDestination,
};

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CreateSession {
    id: SamSessionId,
    destination: SamSessionDestination,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EstablishedSession {
    pub id: SamSessionId,
    pub private_destination: I2pPrivateDestination,
}

impl CreateSession {
    pub fn new(id: SamSessionId, destination: SamSessionDestination) -> Self {
        Self { id, destination }
    }
}

impl private::Sealed for CreateSession {}

impl SamExchange for CreateSession {
    type Output = EstablishedSession;

    fn command(&self) -> SamCommand {
        SamCommand::SessionCreate {
            id: self.id.clone(),
            destination: self.destination.clone(),
        }
    }

    fn conclude(self, reply: SamReply) -> Result<Self::Output, SamProtocolError> {
        let returned_destination = match accepted_reply(SamReplyKind::Session, reply)? {
            SamReply::SessionCreated { destination } => destination,
            reply => return Err(unexpected(SamReplyKind::Session, reply)),
        };
        let private_destination = match (self.destination, returned_destination) {
            (SamSessionDestination::Persistent(destination), _) => destination,
            (
                SamSessionDestination::Transient,
                SamSessionReplyDestination::Returned(destination),
            ) => destination,
            (SamSessionDestination::Transient, SamSessionReplyDestination::Omitted) => {
                return Err(SamProtocolError::MissingTransientSessionDestination);
            }
        };
        Ok(EstablishedSession {
            id: self.id,
            private_destination,
        })
    }
}