1use std::path::Path;
2
3use async_trait::async_trait;
4
5use crate::error::{Error, Result};
6use crate::ftp::FtpClient;
7use crate::sftp::SftpClient;
8use crate::smb::SmbClient;
9use crate::traits::RemoteFileSystem;
10use crate::types::{Config, FileEntry, FileMeta, FtpConfig, Protocol, SftpConfig, SmbConfig};
11
12pub enum Client {
14 Smb(SmbClient),
15 Ftp(FtpClient),
16 Sftp(SftpClient),
17}
18
19impl Client {
20 pub async fn connect_with(config: &Config) -> Result<Self> {
22 let mut client = match config {
23 Config::Smb(cfg) => Client::Smb(SmbClient::new(cfg.clone())),
24 Config::Ftp(cfg) => Client::Ftp(FtpClient::new(cfg.clone())),
25 Config::Sftp(cfg) => Client::Sftp(SftpClient::new(cfg.clone())),
26 };
27 client.connect().await?;
28 Ok(client)
29 }
30
31 pub async fn smb(config: &SmbConfig) -> Result<Self> {
33 Self::connect_with(&Config::Smb(config.clone())).await
34 }
35
36 pub async fn ftp(config: &FtpConfig) -> Result<Self> {
38 Self::connect_with(&Config::Ftp(config.clone())).await
39 }
40
41 pub async fn sftp(config: &SftpConfig) -> Result<Self> {
43 Self::connect_with(&Config::Sftp(config.clone())).await
44 }
45
46 pub fn protocol(&self) -> Protocol {
48 match self {
49 Client::Smb(_) => Protocol::Smb,
50 Client::Ftp(_) => Protocol::Ftp,
51 Client::Sftp(_) => Protocol::Sftp,
52 }
53 }
54}
55
56#[async_trait]
57impl RemoteFileSystem for Client {
58 async fn connect(&mut self) -> Result<()> {
59 match self {
60 Client::Smb(c) => c.connect().await,
61 Client::Ftp(c) => c.connect().await,
62 Client::Sftp(c) => c.connect().await,
63 }
64 }
65
66 async fn disconnect(&mut self) -> Result<()> {
67 match self {
68 Client::Smb(c) => c.disconnect().await,
69 Client::Ftp(c) => c.disconnect().await,
70 Client::Sftp(c) => c.disconnect().await,
71 }
72 }
73
74 fn is_connected(&self) -> bool {
75 match self {
76 Client::Smb(c) => c.is_connected(),
77 Client::Ftp(c) => c.is_connected(),
78 Client::Sftp(c) => c.is_connected(),
79 }
80 }
81
82 async fn list(&mut self, path: &str) -> Result<Vec<FileEntry>> {
83 match self {
84 Client::Smb(c) => c.list(path).await,
85 Client::Ftp(c) => c.list(path).await,
86 Client::Sftp(c) => c.list(path).await,
87 }
88 }
89
90 async fn metadata(&mut self, path: &str) -> Result<FileMeta> {
91 match self {
92 Client::Smb(c) => c.metadata(path).await,
93 Client::Ftp(c) => c.metadata(path).await,
94 Client::Sftp(c) => c.metadata(path).await,
95 }
96 }
97
98 async fn exists(&mut self, path: &str) -> Result<bool> {
99 match self {
100 Client::Smb(c) => c.exists(path).await,
101 Client::Ftp(c) => c.exists(path).await,
102 Client::Sftp(c) => c.exists(path).await,
103 }
104 }
105
106 async fn mkdir(&mut self, path: &str) -> Result<()> {
107 match self {
108 Client::Smb(c) => c.mkdir(path).await,
109 Client::Ftp(c) => c.mkdir(path).await,
110 Client::Sftp(c) => c.mkdir(path).await,
111 }
112 }
113
114 async fn mkdir_all(&mut self, path: &str) -> Result<()> {
115 match self {
116 Client::Smb(c) => c.mkdir_all(path).await,
117 Client::Ftp(c) => c.mkdir_all(path).await,
118 Client::Sftp(c) => c.mkdir_all(path).await,
119 }
120 }
121
122 async fn rmdir(&mut self, path: &str) -> Result<()> {
123 match self {
124 Client::Smb(c) => c.rmdir(path).await,
125 Client::Ftp(c) => c.rmdir(path).await,
126 Client::Sftp(c) => c.rmdir(path).await,
127 }
128 }
129
130 async fn remove_file(&mut self, path: &str) -> Result<()> {
131 match self {
132 Client::Smb(c) => c.remove_file(path).await,
133 Client::Ftp(c) => c.remove_file(path).await,
134 Client::Sftp(c) => c.remove_file(path).await,
135 }
136 }
137
138 async fn remove(&mut self, path: &str) -> Result<()> {
139 match self {
140 Client::Smb(c) => c.remove(path).await,
141 Client::Ftp(c) => c.remove(path).await,
142 Client::Sftp(c) => c.remove(path).await,
143 }
144 }
145
146 async fn rename(&mut self, from: &str, to: &str) -> Result<()> {
147 match self {
148 Client::Smb(c) => c.rename(from, to).await,
149 Client::Ftp(c) => c.rename(from, to).await,
150 Client::Sftp(c) => c.rename(from, to).await,
151 }
152 }
153
154 async fn read(&mut self, path: &str) -> Result<Vec<u8>> {
155 match self {
156 Client::Smb(c) => c.read(path).await,
157 Client::Ftp(c) => c.read(path).await,
158 Client::Sftp(c) => c.read(path).await,
159 }
160 }
161
162 async fn write(&mut self, path: &str, data: &[u8]) -> Result<()> {
163 match self {
164 Client::Smb(c) => c.write(path, data).await,
165 Client::Ftp(c) => c.write(path, data).await,
166 Client::Sftp(c) => c.write(path, data).await,
167 }
168 }
169
170 async fn download(&mut self, remote: &str, local: &Path) -> Result<()> {
171 match self {
172 Client::Smb(c) => c.download(remote, local).await,
173 Client::Ftp(c) => c.download(remote, local).await,
174 Client::Sftp(c) => c.download(remote, local).await,
175 }
176 }
177
178 async fn upload(&mut self, local: &Path, remote: &str) -> Result<()> {
179 match self {
180 Client::Smb(c) => c.upload(local, remote).await,
181 Client::Ftp(c) => c.upload(local, remote).await,
182 Client::Sftp(c) => c.upload(local, remote).await,
183 }
184 }
185}
186
187#[derive(Debug, Default)]
189pub struct ClientBuilder {
190 config: Option<Config>,
191}
192
193impl ClientBuilder {
194 pub fn new() -> Self {
195 Self::default()
196 }
197
198 pub fn smb(mut self, config: SmbConfig) -> Self {
199 self.config = Some(Config::Smb(config));
200 self
201 }
202
203 pub fn ftp(mut self, config: FtpConfig) -> Self {
204 self.config = Some(Config::Ftp(config));
205 self
206 }
207
208 pub fn sftp(mut self, config: SftpConfig) -> Self {
209 self.config = Some(Config::Sftp(config));
210 self
211 }
212
213 pub fn config(mut self, config: Config) -> Self {
214 self.config = Some(config);
215 self
216 }
217
218 pub async fn build(self) -> Result<Client> {
219 let config = self
220 .config
221 .ok_or_else(|| Error::Other("missing connection config".into()))?;
222 Client::connect_with(&config).await
223 }
224}