iscp-rs 1.1.2

iSCPv2 Client Library
Documentation
use std::collections::BTreeMap;

use super::upstream::*;
use super::*;

pub(crate) struct UpstreamStorage {
    stream_id: Uuid,
    is_reliable: bool,
    send_data_points_callback: Option<SendDataPointsCallback>,
    receive_ack_callback: Option<ReceiveAckCallback>,
    chunks: BTreeMap<u32, crate::message::UpstreamChunk>,
    last_received_sequence_number: Option<u32>,
}

impl UpstreamStorage {
    pub fn new(
        stream_id: Uuid,
        qos: QoS,
        send_data_points_callback: Option<SendDataPointsCallback>,
        receive_ack_callback: Option<ReceiveAckCallback>,
    ) -> Self {
        Self {
            stream_id,
            is_reliable: qos == QoS::Reliable,
            send_data_points_callback,
            receive_ack_callback,
            chunks: BTreeMap::new(),
            last_received_sequence_number: None,
        }
    }

    pub async fn add_chunk(
        &mut self,
        chunk: &crate::message::UpstreamChunk,
        dpgs: Vec<DataPointGroup>,
    ) {
        let sequence_number = chunk.stream_chunk.as_ref().unwrap().sequence_number;
        if self.is_reliable {
            self.chunks.insert(sequence_number, chunk.clone());
        }
        if let Some(callback) = &self.send_data_points_callback {
            let chunk = UpstreamChunk {
                sequence_number,
                data_point_groups: dpgs,
            };
            callback(self.stream_id, chunk).await;
        }
    }

    pub async fn process_ack(&mut self, ack: crate::message::UpstreamChunkAck) {
        for result in ack.results {
            if self.last_received_sequence_number.is_none()
                || self.last_received_sequence_number.unwrap() < result.sequence_number
            {
                self.last_received_sequence_number = Some(result.sequence_number);
            }

            if self.is_reliable {
                self.chunks.remove(&result.sequence_number);
            }
            if let Some(callback) = &self.receive_ack_callback {
                match convert_upstream_chunk_result(result) {
                    Ok(result) => callback(self.stream_id, result).await,
                    Err(e) => {
                        log::error!("invalid upstream chunk result: {e}");
                    }
                }
            }
        }
    }

    pub fn iter_chunks(&mut self) -> impl Iterator<Item = crate::message::UpstreamChunk> + '_ {
        self.chunks.values().cloned()
    }

    pub fn last_received_sequence_number(&self) -> Option<u32> {
        self.last_received_sequence_number
    }
}

fn convert_upstream_chunk_result(
    r: crate::message::UpstreamChunkResult,
) -> Result<UpstreamChunkResult, Error> {
    Ok(UpstreamChunkResult {
        sequence_number: r.sequence_number,
        result_code: r
            .result_code
            .try_into()
            .map_err(|_| Error::invalid_value("invalid result_code"))?,
        result_string: r.result_string,
    })
}