@@ -3,7 +3,9 @@ extern crate tls_init;
33mod error;
44
55pub use error:: { DecodeError , EncodeError , Error , Result } ;
6+ use tokio:: sync:: Mutex ;
67
8+ pub mod bucket_client;
79pub mod file_info;
810pub mod file_info_poller;
911pub mod file_sink;
@@ -12,7 +14,7 @@ pub mod file_upload;
1214mod settings;
1315pub mod traits;
1416
15- use std:: path:: Path ;
17+ use std:: { collections :: HashMap , path:: Path , sync :: OnceLock } ;
1618
1719use aws_config:: BehaviorVersion ;
1820use aws_sdk_s3:: primitives:: ByteStream ;
@@ -22,52 +24,82 @@ use chrono::{DateTime, Utc};
2224pub use file_info:: FileInfo ;
2325pub use file_sink:: { FileSink , FileSinkBuilder } ;
2426
27+ pub use bucket_client:: BucketClient ;
2528use futures:: {
2629 future,
2730 stream:: { self , BoxStream } ,
2831 FutureExt , StreamExt , TryFutureExt , TryStreamExt ,
2932} ;
30- pub use settings:: Settings ;
33+ pub use settings:: { BucketSettings , Settings } ;
3134
3235pub type Client = aws_sdk_s3:: Client ;
3336pub type Stream < T > = BoxStream < ' static , Result < T > > ;
3437pub type FileInfoStream = Stream < FileInfo > ;
3538pub type BytesMutStream = Stream < BytesMut > ;
3639
40+ static CLIENT_MAP : OnceLock < Mutex < HashMap < ClientKey , Client > > > = OnceLock :: new ( ) ;
41+
42+ #[ derive( PartialEq , Eq , Hash , Debug ) ]
43+ struct ClientKey {
44+ region : Option < String > ,
45+ endpoint : Option < String > ,
46+ access_key_id : Option < String > ,
47+ secret_access_key : Option < String > ,
48+ }
49+
3750pub async fn new_client (
51+ region : Option < String > ,
3852 endpoint : Option < String > ,
3953 _access_key_id : Option < String > ,
4054 _secret_access_key : Option < String > ,
41- ) -> Client {
55+ ) -> aws_sdk_s3:: Client {
56+ let mut client_map = CLIENT_MAP
57+ . get_or_init ( || Mutex :: new ( HashMap :: new ( ) ) )
58+ . lock ( )
59+ . await ;
60+
61+ let key = ClientKey {
62+ region : region. clone ( ) ,
63+ endpoint : endpoint. clone ( ) ,
64+ access_key_id : _access_key_id. clone ( ) ,
65+ secret_access_key : _secret_access_key. clone ( ) ,
66+ } ;
67+
68+ if let Some ( client) = client_map. get ( & key) {
69+ tracing:: debug!( params = ?key, "Using existing file-store s3 client" ) ;
70+ return client. clone ( ) ;
71+ }
72+
4273 let config = aws_config:: defaults ( BehaviorVersion :: latest ( ) ) . load ( ) . await ;
4374
4475 let mut s3_config = aws_sdk_s3:: config:: Builder :: from ( & config) ;
45- if let Some ( endpoint) = endpoint {
46- s3_config = s3_config. endpoint_url ( endpoint) ;
76+
77+ if let Some ( region_str) = region {
78+ s3_config = s3_config. region ( aws_config:: Region :: new ( region_str) ) ;
4779 }
4880
49- # [ cfg ( feature = "local" ) ]
50- {
81+ if let Some ( endpoint ) = endpoint {
82+ s3_config = s3_config . endpoint_url ( endpoint ) ;
5183 // NOTE(mj): If you see something like a DNS error, this is probably
5284 // the culprit. Need to find a way to make this configurable. It
5385 // would be nice to allow the "local" feature to be active, but not
5486 // enforce path style.
5587 s3_config = s3_config. force_path_style ( true ) ;
88+ }
5689
57- // Set a default region for local development (MinIO doesn't care about the region)
58- s3_config = s3_config. region ( aws_config:: Region :: new ( "us-east-1" ) ) ;
59-
60- if let Some ( ( access_key_id, secret_access_key) ) = _access_key_id. zip ( _secret_access_key) {
61- let creds = aws_sdk_s3:: config:: Credentials :: builder ( )
62- . provider_name ( "Static" )
63- . access_key_id ( access_key_id)
64- . secret_access_key ( secret_access_key) ;
90+ if let Some ( ( access_key_id, secret_access_key) ) = _access_key_id. zip ( _secret_access_key) {
91+ let creds = aws_sdk_s3:: config:: Credentials :: builder ( )
92+ . provider_name ( "Static" )
93+ . access_key_id ( access_key_id)
94+ . secret_access_key ( secret_access_key) ;
6595
66- s3_config = s3_config. credentials_provider ( creds. build ( ) ) ;
67- }
96+ s3_config = s3_config. credentials_provider ( creds. build ( ) ) ;
6897 }
6998
70- Client :: from_conf ( s3_config. build ( ) )
99+ tracing:: debug!( params = ?key, "Creating new file-store s3 client" ) ;
100+ let client = Client :: from_conf ( s3_config. build ( ) ) ;
101+ client_map. insert ( key, client. clone ( ) ) ;
102+ client
71103}
72104
73105pub fn list_files < A , B > (
0 commit comments