1+ using System ;
2+ using System . Collections . Generic ;
3+ using System . IO ;
4+ using System . Linq ;
5+ using System . Net . Sockets ;
6+ using System . Threading ;
7+ using System . Threading . Tasks ;
8+ using FluentFTP ;
9+ using FluentFTP . Exceptions ;
10+ using SharpGrip . FileSystem . Constants ;
11+ using SharpGrip . FileSystem . Exceptions ;
12+ using SharpGrip . FileSystem . Extensions ;
13+ using SharpGrip . FileSystem . Models ;
14+ using SharpGrip . FileSystem . Utilities ;
15+ using DirectoryNotFoundException = SharpGrip . FileSystem . Exceptions . DirectoryNotFoundException ;
16+ using FileNotFoundException = SharpGrip . FileSystem . Exceptions . FileNotFoundException ;
17+
18+ namespace SharpGrip . FileSystem . Adapters . Ftp
19+ {
20+ public class FtpAdapter : Adapter < FtpAdapterConfiguration , string , string >
21+ {
22+ private readonly IAsyncFtpClient client ;
23+
24+ public FtpAdapter ( string prefix , string rootPath , IAsyncFtpClient client , Action < FtpAdapterConfiguration > ? configuration = null ) : base ( prefix , rootPath , configuration )
25+ {
26+ this . client = client ;
27+ }
28+
29+ public override void Dispose ( )
30+ {
31+ client . Dispose ( ) ;
32+ }
33+
34+ public override async Task ConnectAsync ( CancellationToken cancellationToken = default )
35+ {
36+ if ( client . IsConnected )
37+ {
38+ return ;
39+ }
40+
41+ try
42+ {
43+ Logger . LogStartConnectingAdapter ( this ) ;
44+ await client . Connect ( cancellationToken ) ;
45+ Logger . LogFinishedConnectingAdapter ( this ) ;
46+ }
47+ catch ( Exception exception )
48+ {
49+ throw Exception ( exception ) ;
50+ }
51+ }
52+
53+ public override async Task < IFile > GetFileAsync ( string virtualPath , CancellationToken cancellationToken = default )
54+ {
55+ var path = GetPath ( virtualPath ) ;
56+
57+ try
58+ {
59+ var file = await client . GetObjectInfo ( path , token : cancellationToken ) ;
60+
61+ if ( file == null || file . Type != FtpObjectType . File )
62+ {
63+ throw new FileNotFoundException ( path , Prefix ) ;
64+ }
65+
66+ return ModelFactory . CreateFile ( file , virtualPath ) ;
67+ }
68+ catch ( Exception exception )
69+ {
70+ throw Exception ( exception ) ;
71+ }
72+ }
73+
74+ public override async Task < IDirectory > GetDirectoryAsync ( string virtualPath , CancellationToken cancellationToken = default )
75+ {
76+ var path = GetPath ( virtualPath ) ;
77+
78+ try
79+ {
80+ var directory = await client . GetObjectInfo ( path , token : cancellationToken ) ;
81+
82+ if ( directory == null || directory . Type != FtpObjectType . Directory )
83+ {
84+ throw new DirectoryNotFoundException ( path , Prefix ) ;
85+ }
86+
87+ return ModelFactory . CreateDirectory ( directory , virtualPath ) ;
88+ }
89+ catch ( Exception exception )
90+ {
91+ throw Exception ( exception ) ;
92+ }
93+ }
94+
95+ public override async Task < IEnumerable < IFile > > GetFilesAsync ( string virtualPath = "" , CancellationToken cancellationToken = default )
96+ {
97+ await GetDirectoryAsync ( virtualPath , cancellationToken ) ;
98+ var path = GetPath ( virtualPath ) ;
99+
100+ try
101+ {
102+ var ftpListItems = await client . GetListing ( path , cancellationToken ) ;
103+
104+ return ftpListItems . Where ( file => file . Type == FtpObjectType . File ) . Select ( file => ModelFactory . CreateFile ( file , GetVirtualPath ( file . FullName ) ) ) ;
105+ }
106+ catch ( Exception exception )
107+ {
108+ throw Exception ( exception ) ;
109+ }
110+ }
111+
112+ public override async Task < IEnumerable < IDirectory > > GetDirectoriesAsync ( string virtualPath = "" , CancellationToken cancellationToken = default )
113+ {
114+ await GetDirectoryAsync ( virtualPath , cancellationToken ) ;
115+ var path = GetPath ( virtualPath ) ;
116+
117+ try
118+ {
119+ var ftpListItems = await client . GetListing ( path , cancellationToken ) ;
120+
121+ return ftpListItems . Where ( file => file . Type == FtpObjectType . Directory ) . Select ( file => ModelFactory . CreateDirectory ( file , GetVirtualPath ( file . FullName ) ) ) ;
122+ }
123+ catch ( Exception exception )
124+ {
125+ throw Exception ( exception ) ;
126+ }
127+ }
128+
129+ public override async Task CreateDirectoryAsync ( string virtualPath , CancellationToken cancellationToken = default )
130+ {
131+ if ( await DirectoryExistsAsync ( virtualPath , cancellationToken ) )
132+ {
133+ throw new DirectoryExistsException ( GetPath ( virtualPath ) , Prefix ) ;
134+ }
135+
136+ try
137+ {
138+ await client . CreateDirectory ( GetPath ( virtualPath ) , cancellationToken ) ;
139+ }
140+ catch ( Exception exception )
141+ {
142+ throw Exception ( exception ) ;
143+ }
144+ }
145+
146+ public override async Task DeleteDirectoryAsync ( string virtualPath , CancellationToken cancellationToken = default )
147+ {
148+ await GetDirectoryAsync ( virtualPath , cancellationToken ) ;
149+
150+ try
151+ {
152+ await client . DeleteDirectory ( GetPath ( virtualPath ) , cancellationToken ) ;
153+ }
154+ catch ( Exception exception )
155+ {
156+ throw Exception ( exception ) ;
157+ }
158+ }
159+
160+ public override async Task DeleteFileAsync ( string virtualPath , CancellationToken cancellationToken = default )
161+ {
162+ await GetFileAsync ( virtualPath , cancellationToken ) ;
163+
164+ try
165+ {
166+ await client . DeleteFile ( GetPath ( virtualPath ) , cancellationToken ) ;
167+ }
168+ catch ( Exception exception )
169+ {
170+ throw Exception ( exception ) ;
171+ }
172+ }
173+
174+ public override async Task < Stream > ReadFileStreamAsync ( string virtualPath , CancellationToken cancellationToken = default )
175+ {
176+ await GetFileAsync ( virtualPath , cancellationToken ) ;
177+
178+ try
179+ {
180+ var fileStream = await client . OpenRead ( GetPath ( virtualPath ) , token : cancellationToken ) ;
181+
182+ return await StreamUtilities . CopyContentsToMemoryStreamAsync ( fileStream , true , cancellationToken ) ;
183+ }
184+ catch ( Exception exception )
185+ {
186+ throw Exception ( exception ) ;
187+ }
188+ }
189+
190+ public override async Task WriteFileAsync ( string virtualPath , Stream contents , bool overwrite = false , CancellationToken cancellationToken = default )
191+ {
192+ if ( ! overwrite && await FileExistsAsync ( virtualPath , cancellationToken ) )
193+ {
194+ throw new FileExistsException ( GetPath ( virtualPath ) , Prefix ) ;
195+ }
196+
197+ try
198+ {
199+ contents . Seek ( 0 , SeekOrigin . Begin ) ;
200+
201+ using var writeStream = await client . OpenWrite ( GetPath ( virtualPath ) , token : cancellationToken ) ;
202+
203+ await contents . CopyToAsync ( writeStream , FileSystemConstants . Streaming . DefaultMemoryStreamBufferSize , cancellationToken ) ;
204+ await writeStream . FlushAsync ( cancellationToken ) ;
205+ }
206+ catch ( Exception exception )
207+ {
208+ throw Exception ( exception ) ;
209+ }
210+ }
211+
212+ public override async Task AppendFileAsync ( string virtualPath , Stream contents , CancellationToken cancellationToken = default )
213+ {
214+ await GetFileAsync ( virtualPath , cancellationToken ) ;
215+
216+ try
217+ {
218+ using var fileStream = await client . OpenAppend ( GetPath ( virtualPath ) , token : cancellationToken ) ;
219+
220+ await contents . CopyToAsync ( fileStream ) ;
221+ }
222+ catch ( Exception exception )
223+ {
224+ throw new AdapterRuntimeException ( exception ) ;
225+ }
226+ }
227+
228+ protected override Exception Exception ( Exception exception )
229+ {
230+ if ( exception is FileSystemException )
231+ {
232+ return exception ;
233+ }
234+
235+ if ( exception is SocketException socketException )
236+ {
237+ return new ConnectionException ( socketException ) ;
238+ }
239+
240+ if ( exception is FtpAuthenticationException ftpAuthenticationException )
241+ {
242+ return new ConnectionException ( ftpAuthenticationException ) ;
243+ }
244+
245+ if ( exception is FtpSecurityNotAvailableException ftpSecurityNotAvailableException )
246+ {
247+ return new ConnectionException ( ftpSecurityNotAvailableException ) ;
248+ }
249+
250+ return new AdapterRuntimeException ( exception ) ;
251+ }
252+ }
253+ }
0 commit comments