126 lines · 3.8 KB · Rust
RawDownload
use async_trait::async_trait;use bstr::BString;use futures_io::{AsyncRead, AsyncWrite};use futures_lite::AsyncWriteExt;use git_packetline::PacketLine; use crate::{    client::{self, capabilities, git, Capabilities, SetServiceResponse},    Protocol, Service,}; impl<R, W> client::TransportWithoutIO for git::Connection<R, W>where    R: AsyncRead + Unpin,    W: AsyncWrite + Unpin,{    fn request(        &mut self,        write_mode: client::WriteMode,        on_into_read: client::MessageKind,    ) -> Result<client::RequestWriter<'_>, client::Error> {        Ok(client::RequestWriter::new_from_bufread(            &mut self.writer,            Box::new(self.line_provider.as_read_without_sidebands()),            write_mode,            on_into_read,        ))    }    fn to_url(&self) -> String {        self.custom_url.as_ref().map_or_else(            || {                git_url::Url {                    scheme: git_url::Scheme::File,                    user: None,                    host: None,                    port: None,                    path: self.path.clone(),                }                .to_string()            },            |url| url.clone(),        )    }     /// We implement this in a paranoid and safe way, not allowing downgrade to V1 which    /// could send large amounts of refs in case we didn't want to support V1.    fn supported_protocol_versions(&self) -> &[Protocol] {        if self.desired_version == Protocol::V1 {            &[]        } else {            &self.supported_versions        }    }     fn connection_persists_across_multiple_requests(&self) -> bool {        true    }} #[async_trait(?Send)]impl<R, W> client::Transport for git::Connection<R, W>where    R: AsyncRead + Unpin,    W: AsyncWrite + Unpin,{    async fn handshake<'a>(        &mut self,        service: Service,        extra_parameters: &'a [(&'a str, Option<&'a str>)],    ) -> Result<SetServiceResponse<'_>, client::Error> {        if self.mode == git::ConnectMode::Daemon {            let mut line_writer = git_packetline::Writer::new(&mut self.writer).binary_mode();            line_writer                .write_all(&git::message::connect(                    service,                    self.desired_version,                    &self.path,                    self.virtual_host.as_ref(),                    extra_parameters,                ))                .await?;            line_writer.flush().await?;        }         let capabilities::recv::Outcome {            capabilities,            refs,            protocol: actual_protocol,        } = Capabilities::from_lines_with_version_detection(&mut self.line_provider).await?;        Ok(SetServiceResponse {            actual_protocol,            capabilities,            refs,        })    }} impl<R, W> git::Connection<R, W>where    R: AsyncRead + Unpin,    W: AsyncWrite + Unpin,{    /// Create a connection from the given `read` and `write`, asking for `desired_version` as preferred protocol    /// and the transfer of the repository at `repository_path`.    ///    /// `virtual_host` along with a port to which to connect to, while `mode` determines the kind of endpoint to connect to.    pub fn new(        read: R,        write: W,        desired_version: Protocol,        repository_path: impl Into<BString>,        virtual_host: Option<(impl Into<String>, Option<u16>)>,        mode: git::ConnectMode,    ) -> Self {        git::Connection {            writer: write,            line_provider: git_packetline::StreamingPeekableIter::new(read, &[PacketLine::Flush]),            path: repository_path.into(),            virtual_host: virtual_host.map(|(h, p)| (h.into(), p)),            desired_version,            custom_url: None,            supported_versions: [desired_version],            mode,        }    }}