Skip to content

Commit d0cf45b

Browse files
authored
Merge pull request #121 from AvivNaaman/imutable-client
Make client immutable, to allow easier parallel API
2 parents 75ba15d + 5c782c3 commit d0cf45b

File tree

1 file changed

+32
-22
lines changed

1 file changed

+32
-22
lines changed

smb/src/client/smb_client.rs

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
use std::{collections::HashMap, str::FromStr};
2-
3-
use maybe_async::maybe_async;
4-
51
use crate::{
62
Connection, Error, FileCreateArgs, Resource, Session, Tree,
73
packets::{
@@ -10,15 +6,19 @@ use crate::{
106
smb2::Status,
117
},
128
resource::Pipe,
9+
sync_helpers::*,
1310
};
11+
use maybe_async::maybe_async;
12+
use std::sync::Arc;
13+
use std::{collections::HashMap, str::FromStr};
1414

1515
use super::{config::ClientConfig, unc_path::UncPath};
1616

1717
/// A High-level SMB client interface.
1818
pub struct Client {
1919
config: ClientConfig,
2020

21-
connections: HashMap<UncPath, OpenedConnectionInfo>,
21+
connections: Mutex<HashMap<UncPath, Arc<OpenedConnectionInfo>>>,
2222
}
2323

2424
struct OpenedConnectionInfo {
@@ -33,13 +33,13 @@ impl Client {
3333
pub fn new(config: ClientConfig) -> Self {
3434
Client {
3535
config,
36-
connections: HashMap::new(),
36+
connections: Mutex::new(HashMap::new()),
3737
}
3838
}
3939

4040
#[maybe_async]
41-
pub async fn close(&mut self) -> crate::Result<()> {
42-
self.connections.clear();
41+
pub async fn close(&self) -> crate::Result<()> {
42+
self.connections.lock().await?.clear();
4343
Ok(())
4444
}
4545

@@ -67,7 +67,7 @@ impl Client {
6767

6868
#[maybe_async]
6969
pub async fn share_connect(
70-
&mut self,
70+
&self,
7171
unc: &UncPath,
7272
user_name: &str,
7373
password: String,
@@ -80,7 +80,8 @@ impl Client {
8080

8181
let share_unc = unc.clone().with_no_path();
8282

83-
if self.connections.contains_key(&share_unc) {
83+
let mut connections = self.connections.lock().await?;
84+
if connections.contains_key(&share_unc) {
8485
log::warn!("Connection already exists for this UNC path. Reusing it.");
8586
return Ok(());
8687
}
@@ -102,14 +103,19 @@ impl Client {
102103
}
103104

104105
log::debug!("Connected to share {share_unc} with user {user_name}");
105-
self.connections.insert(share_unc, opened_conn_info);
106+
connections.insert(share_unc, Arc::new(opened_conn_info));
106107

107108
Ok(())
108109
}
109110

110-
fn get_opened_conn_for_path(&self, unc: &UncPath) -> crate::Result<&OpenedConnectionInfo> {
111-
if let Some(cst) = self.connections.get(&unc.clone().with_no_path()) {
112-
Ok(cst)
111+
#[maybe_async]
112+
async fn get_opened_conn_for_path(
113+
&self,
114+
unc: &UncPath,
115+
) -> crate::Result<Arc<OpenedConnectionInfo>> {
116+
let connections = self.connections.lock().await?;
117+
if let Some(cst) = connections.get(&unc.clone().with_no_path()) {
118+
Ok(cst.clone())
113119
} else {
114120
Err(crate::Error::InvalidArgument(format!(
115121
"No connection found for {unc}. Use `share_connect` to create one.",
@@ -123,7 +129,7 @@ impl Client {
123129
path: &UncPath,
124130
args: &FileCreateArgs,
125131
) -> crate::Result<Resource> {
126-
let conn_info = self.get_opened_conn_for_path(path)?;
132+
let conn_info = self.get_opened_conn_for_path(path).await?;
127133
conn_info
128134
.tree
129135
.create(path.path.as_deref().unwrap_or(""), args)
@@ -132,7 +138,7 @@ impl Client {
132138

133139
#[maybe_async]
134140
pub async fn create_file(
135-
&mut self,
141+
&self,
136142
path: &UncPath,
137143
args: &FileCreateArgs,
138144
) -> crate::Result<Resource> {
@@ -173,10 +179,10 @@ impl Client {
173179
}
174180
}
175181

176-
struct DfsResolver<'a>(&'a mut Client);
182+
struct DfsResolver<'a>(&'a Client);
177183

178184
impl<'a> DfsResolver<'a> {
179-
fn new(client: &'a mut Client) -> Self {
185+
fn new(client: &'a Client) -> Self {
180186
DfsResolver(client)
181187
}
182188

@@ -192,7 +198,8 @@ impl<'a> DfsResolver<'a> {
192198
// Re-use the same credentials for the DFS referral.
193199
let dfs_creds = self
194200
.0
195-
.get_opened_conn_for_path(dfs_path)?
201+
.get_opened_conn_for_path(dfs_path)
202+
.await?
196203
.creds
197204
.clone()
198205
.ok_or_else(|| {
@@ -232,14 +239,17 @@ impl<'a> DfsResolver<'a> {
232239
log::debug!("Resolving DFS referral for {unc}");
233240
let dfs_path_string = unc.to_string();
234241

235-
let dfs_root = self.0.get_opened_conn_for_path(unc)?.tree.as_dfs_tree()?;
236-
237-
let dfs_refs = dfs_root.dfs_get_referrals(&dfs_path_string).await?;
242+
let dfs_refs = {
243+
let conn = &self.0.get_opened_conn_for_path(unc).await?;
244+
let dfs_root = conn.tree.as_dfs_tree()?;
245+
dfs_root.dfs_get_referrals(&dfs_path_string).await?
246+
};
238247
if !dfs_refs.referral_header_flags.storage_servers() {
239248
return Err(Error::InvalidMessage(
240249
"DFS referral does not contain storage servers".to_string(),
241250
));
242251
}
252+
243253
let mut paths = vec![];
244254
// Resolve the DFS referral entries.
245255
for (indx, curr_referral) in dfs_refs.referral_entries.iter().enumerate() {

0 commit comments

Comments
 (0)