gproxy-transform 3.0.0-alpha.0

GPROXY v3 pairwise protocol transforms
Documentation
use bytes::Bytes;
use gproxy_protocol::StreamFraming;

use super::super::json_array::{JsonArrayDecoder, JsonArrayEncoder};
use super::super::{SseDecoder, SseFrame};
use crate::TransformError;

pub(super) enum FrameDecoder {
    Sse(SseDecoder),
    JsonArray(JsonArrayDecoder),
}

pub(super) enum FrameEncoder {
    Sse,
    JsonArray {
        decoder: SseDecoder,
        encoder: JsonArrayEncoder,
        done: bool,
    },
}

impl FrameDecoder {
    pub(super) fn new(framing: StreamFraming) -> Result<Self, TransformError> {
        match framing {
            StreamFraming::Sse => Ok(Self::Sse(SseDecoder::default())),
            StreamFraming::JsonArray => Ok(Self::JsonArray(JsonArrayDecoder::default())),
            StreamFraming::WebSocket => Err(TransformError::shape(
                "stream framing",
                "websocket framing requires a websocket transform",
            )),
        }
    }

    pub(super) fn push(&mut self, chunk: &[u8]) -> Result<Vec<SseFrame>, TransformError> {
        match self {
            Self::Sse(decoder) => decoder.push(chunk),
            Self::JsonArray(decoder) => decoder.push(chunk),
        }
    }

    pub(super) fn finish(&mut self) -> Result<Vec<SseFrame>, TransformError> {
        match self {
            Self::Sse(decoder) => Ok(decoder.finish()?.into_iter().collect()),
            Self::JsonArray(decoder) => decoder.finish(),
        }
    }
}

impl FrameEncoder {
    pub(super) fn new(framing: StreamFraming) -> Result<Self, TransformError> {
        match framing {
            StreamFraming::Sse => Ok(Self::Sse),
            StreamFraming::JsonArray => Ok(Self::JsonArray {
                decoder: SseDecoder::default(),
                encoder: JsonArrayEncoder::default(),
                done: false,
            }),
            StreamFraming::WebSocket => Err(TransformError::shape(
                "stream framing",
                "websocket framing requires a websocket transform",
            )),
        }
    }

    pub(super) fn push(&mut self, chunks: Vec<Bytes>) -> Result<Vec<Bytes>, TransformError> {
        match self {
            Self::Sse => Ok(chunks),
            Self::JsonArray {
                decoder,
                encoder,
                done,
            } => {
                let mut output = Vec::new();
                for chunk in chunks {
                    for frame in decoder.push(&chunk)? {
                        encode_array_frame(encoder, done, frame, &mut output)?;
                    }
                }
                Ok(output)
            }
        }
    }

    pub(super) fn finish(&mut self) -> Result<Vec<Bytes>, TransformError> {
        match self {
            Self::Sse => Ok(Vec::new()),
            Self::JsonArray {
                decoder,
                encoder,
                done,
            } => {
                let mut output = Vec::new();
                if let Some(frame) = decoder.finish()? {
                    encode_array_frame(encoder, done, frame, &mut output)?;
                }
                output.push(encoder.finish()?);
                Ok(output)
            }
        }
    }
}

fn encode_array_frame(
    encoder: &mut JsonArrayEncoder,
    done: &mut bool,
    frame: SseFrame,
    output: &mut Vec<Bytes>,
) -> Result<(), TransformError> {
    if frame.data == "[DONE]" {
        if *done {
            return Err(TransformError::shape(
                "stream framing",
                "duplicate [DONE] sentinel",
            ));
        }
        *done = true;
        return Ok(());
    }
    if *done {
        return Err(TransformError::shape(
            "stream framing",
            "data followed [DONE] sentinel",
        ));
    }
    output.push(encoder.push(&frame.data)?);
    Ok(())
}