gix_protocol/
util.rs

1/// The name of the `git` client in a format suitable for presentation to a `git` server, using `name` as user-defined portion of the value.
2pub fn agent(name: impl Into<String>) -> String {
3    let mut name = name.into();
4    if !name.starts_with("git/") {
5        name.insert_str(0, "git/");
6    }
7    name
8}
9#[cfg(any(feature = "blocking-client", feature = "async-client"))]
10mod with_transport {
11    use gix_transport::client::Transport;
12
13    /// Send a message to indicate the remote side that there is nothing more to expect from us, indicating a graceful shutdown.
14    /// If `trace` is `true`, all packetlines received or sent will be passed to the facilities of the `gix-trace` crate.
15    #[maybe_async::maybe_async]
16    pub async fn indicate_end_of_interaction(
17        mut transport: impl gix_transport::client::Transport,
18        trace: bool,
19    ) -> Result<(), gix_transport::client::Error> {
20        // An empty request marks the (early) end of the interaction. Only relevant in stateful transports though.
21        if transport.connection_persists_across_multiple_requests() {
22            transport
23                .request(
24                    gix_transport::client::WriteMode::Binary,
25                    gix_transport::client::MessageKind::Flush,
26                    trace,
27                )?
28                .into_read()
29                .await?;
30        }
31        Ok(())
32    }
33
34    /// A utility to automatically send a flush packet when the instance is dropped, assuring a graceful termination of any
35    /// interaction with the server.
36    pub struct SendFlushOnDrop<T>
37    where
38        T: Transport,
39    {
40        /// The actual transport instance.
41        pub inner: T,
42        /// If `true`, the packetline used to indicate the end of interaction will be traced using `gix-trace`.
43        trace_packetlines: bool,
44        /// If `true`, we should not send another flush packet.
45        flush_packet_sent: bool,
46    }
47
48    impl<T> SendFlushOnDrop<T>
49    where
50        T: Transport,
51    {
52        /// Create a new instance with `transport`, while optionally tracing packetlines with `trace_packetlines`.
53        pub fn new(transport: T, trace_packetlines: bool) -> Self {
54            Self {
55                inner: transport,
56                trace_packetlines,
57                flush_packet_sent: false,
58            }
59        }
60
61        /// Useful to explicitly invalidate the connection by sending a flush-packet.
62        /// This will happen exactly once, and it is not considered an error to call it multiple times.
63        ///
64        /// For convenience, this is not consuming, but could be to assure the underlying transport isn't used anymore.
65        #[maybe_async::maybe_async]
66        pub async fn indicate_end_of_interaction(&mut self) -> Result<(), gix_transport::client::Error> {
67            if self.flush_packet_sent {
68                return Ok(());
69            }
70
71            self.flush_packet_sent = true;
72            indicate_end_of_interaction(&mut self.inner, self.trace_packetlines).await
73        }
74    }
75
76    impl<T> Drop for SendFlushOnDrop<T>
77    where
78        T: Transport,
79    {
80        fn drop(&mut self) {
81            #[cfg(feature = "async-client")]
82            {
83                // TODO: this should be an async drop once the feature is available.
84                //       Right now we block the executor by forcing this communication, but that only
85                //       happens if the user didn't actually try to receive a pack, which consumes the
86                //       connection in an async context.
87                crate::futures_lite::future::block_on(self.indicate_end_of_interaction()).ok();
88            }
89            #[cfg(not(feature = "async-client"))]
90            {
91                self.indicate_end_of_interaction().ok();
92            }
93        }
94    }
95}
96#[cfg(any(feature = "blocking-client", feature = "async-client"))]
97pub use with_transport::*;