openssh_sftp_client/
options.rs

1use std::{
2    num::{NonZeroU16, NonZeroUsize},
3    time::Duration,
4};
5
6#[cfg(feature = "__ci-tests")]
7use std::num::NonZeroU32;
8
9/// Options when creating [`super::Sftp`].
10#[derive(Debug, Copy, Clone, Default)]
11pub struct SftpOptions {
12    read_end_buffer_size: Option<NonZeroUsize>,
13    write_end_buffer_size: Option<NonZeroUsize>,
14    flush_interval: Option<Duration>,
15    max_pending_requests: Option<NonZeroU16>,
16    tokio_compat_file_write_limit: Option<NonZeroUsize>,
17
18    #[cfg(feature = "__ci-tests")]
19    max_read_len: Option<NonZeroU32>,
20    #[cfg(feature = "__ci-tests")]
21    max_write_len: Option<NonZeroU32>,
22}
23
24impl SftpOptions {
25    /// Create a new [`SftpOptions`].
26    pub const fn new() -> Self {
27        Self {
28            read_end_buffer_size: None,
29            write_end_buffer_size: None,
30            flush_interval: None,
31            max_pending_requests: None,
32            tokio_compat_file_write_limit: None,
33
34            #[cfg(feature = "__ci-tests")]
35            max_read_len: None,
36            #[cfg(feature = "__ci-tests")]
37            max_write_len: None,
38        }
39    }
40
41    /// Set `flush_interval`, default value is 0.5 ms.
42    ///
43    /// `flush_interval` decides the maximum time your requests would stay
44    /// in the write buffer before it is actually sent to the remote.
45    ///
46    /// If another thread is doing flushing, then the internal `flush_task`
47    /// [`super::Sftp`] started would wait for another `flush_interval`.
48    ///
49    /// Setting it to be larger might improve overall performance by grouping
50    /// writes and reducing the overhead of packet sent over network, but it
51    /// might also increase latency, so be careful when setting the
52    /// `flush_interval`.
53    ///
54    /// If `flush_interval` is set to 0, then every packet
55    /// is flushed immediately.
56    ///
57    /// NOTE that it is perfectly OK to set `flush_interval` to 0 and
58    /// it would not slowdown the program, as flushing is only performed
59    /// on daemon.
60    #[must_use]
61    pub const fn flush_interval(mut self, flush_interval: Duration) -> Self {
62        self.flush_interval = Some(flush_interval);
63        self
64    }
65
66    pub(super) fn get_flush_interval(&self) -> Duration {
67        self.flush_interval
68            .unwrap_or_else(|| Duration::from_micros(500))
69    }
70
71    /// Set `max_pending_requests`.
72    ///
73    /// If the pending_requests is larger than max_pending_requests, then the
74    /// flush task will flush the write buffer without waiting for `flush_interval`.
75    ///
76    /// It is set to 100 by default.
77    #[must_use]
78    pub const fn max_pending_requests(mut self, max_pending_requests: NonZeroU16) -> Self {
79        self.max_pending_requests = Some(max_pending_requests);
80        self
81    }
82
83    pub(super) fn get_max_pending_requests(&self) -> u16 {
84        self.max_pending_requests
85            .map(NonZeroU16::get)
86            .unwrap_or(100)
87    }
88
89    /// Set the init buffer size for requests.
90    /// It is used to store [`bytes::Bytes`] and it will be resized
91    /// to fit the pending requests.
92    ///
93    /// NOTE that sftp uses double buffer for efficient flushing
94    /// without blocking the writers.
95    ///
96    /// It is set to 100 by default.
97    #[must_use]
98    pub const fn requests_buffer_size(mut self, buffer_size: NonZeroUsize) -> Self {
99        self.write_end_buffer_size = Some(buffer_size);
100        self
101    }
102
103    pub(super) fn get_write_end_buffer_size(&self) -> NonZeroUsize {
104        self.write_end_buffer_size
105            .unwrap_or_else(|| NonZeroUsize::new(100).unwrap())
106    }
107
108    /// Set the init buffer size for responses.
109    /// If the header of the response is larger than the buffer, then the buffer
110    /// will be resized to fit the size of the header.
111    ///
112    /// It is set to 1024 by default.
113    #[must_use]
114    pub const fn responses_buffer_size(mut self, buffer_size: NonZeroUsize) -> Self {
115        self.read_end_buffer_size = Some(buffer_size);
116        self
117    }
118
119    pub(super) fn get_read_end_buffer_size(&self) -> NonZeroUsize {
120        self.read_end_buffer_size
121            .unwrap_or_else(|| NonZeroUsize::new(1024).unwrap())
122    }
123
124    /// Set the write buffer limit for tokio compat file.
125    /// If [`crate::file::TokioCompatFile`] has hit the write buffer limit
126    /// set here, then it will flush one write buffer and continue
127    /// sending (part of) the buffer to the server, which could be buffered.
128    ///
129    /// It is set to 640KB (640 * 1024 bytes) by default.
130    #[must_use]
131    pub const fn tokio_compat_file_write_limit(mut self, limit: NonZeroUsize) -> Self {
132        self.tokio_compat_file_write_limit = Some(limit);
133        self
134    }
135
136    pub(super) fn get_tokio_compat_file_write_limit(&self) -> usize {
137        self.tokio_compat_file_write_limit
138            .map(NonZeroUsize::get)
139            .unwrap_or(640 * 1024)
140    }
141}
142
143#[cfg(feature = "__ci-tests")]
144impl SftpOptions {
145    /// Set `max_read_len`.
146    ///
147    /// It can be used to reduce `max_read_len`, but cannot be used
148    /// to increase `max_read_len`.
149    #[must_use]
150    pub const fn max_read_len(mut self, max_read_len: NonZeroU32) -> Self {
151        self.max_read_len = Some(max_read_len);
152        self
153    }
154
155    pub(super) fn get_max_read_len(&self) -> Option<u32> {
156        self.max_read_len.map(NonZeroU32::get)
157    }
158
159    /// Set `max_write_len`.
160    ///
161    /// It can be used to reduce `max_write_len`, but cannot be used
162    /// to increase `max_write_len`.
163    #[must_use]
164    pub const fn max_write_len(mut self, max_write_len: NonZeroU32) -> Self {
165        self.max_write_len = Some(max_write_len);
166        self
167    }
168
169    pub(super) fn get_max_write_len(&self) -> Option<u32> {
170        self.max_write_len.map(NonZeroU32::get)
171    }
172}
173
174#[cfg(not(feature = "__ci-tests"))]
175impl SftpOptions {
176    pub(super) const fn get_max_read_len(&self) -> Option<u32> {
177        None
178    }
179
180    pub(super) const fn get_max_write_len(&self) -> Option<u32> {
181        None
182    }
183}