@@ -21,16 +21,18 @@ def __init__(
2121 self ,
2222 elastic : AsyncElasticsearch | None = None ,
2323 s3_client : S3Client | None = None ,
24+ s3_proxy_client : S3Client | None = None ,
2425 s3_context_stack : AsyncExitStack | None = None ,
2526 http_client : httpx .AsyncClient | None = None ,
2627 ):
2728 self .elastic = elastic
2829 self .s3_client = s3_client
30+ self .s3_proxy_client = s3_client
2931 self .s3_context_stack = s3_context_stack
3032 self .http_client = http_client
3133
3234
33- CONNECTIONS = AmcatConnections (s3_client = None , elastic = None , http_client = None ) # type: ignore
35+ CONNECTIONS = AmcatConnections (s3_client = None , s3_proxy_client = None , elastic = None , http_client = None ) # type: ignore
3436
3537
3638@asynccontextmanager
@@ -55,7 +57,7 @@ async def amcat_connections() -> AsyncGenerator[None, None]:
5557
5658def es () -> AsyncElasticsearch :
5759 """
58- Use this function to access the elasticsearch connection.
60+ Access the elasticsearch connection.
5961 """
6062 if CONNECTIONS .elastic is None :
6163 raise ConnectionError ("Elasticsearch connection not initialized" )
@@ -64,22 +66,38 @@ def es() -> AsyncElasticsearch:
6466
6567def s3 () -> S3Client :
6668 """
67- Use this function to access the s3 client.
69+ Access the s3 client.
6870 """
6971 if CONNECTIONS .s3_client is None :
7072 raise ConnectionError ("S3 client not started" )
7173 return CONNECTIONS .s3_client
7274
7375
76+ def s3_public () -> S3Client :
77+ """
78+ Only use this for creating presigned requests for the public
79+ s3 server. If the s3 server is not publicly accessible, set s3_use_proxy
80+ to use the s3_proxy_client, which signs urls
81+ """
82+ settings = get_settings ()
83+ use_proxy = settings .s3_use_proxy and not settings .test_mode
84+ s3 = CONNECTIONS .s3_proxy_client if use_proxy else CONNECTIONS .s3_client
85+ if s3 is None :
86+ raise ConnectionError ("S3 client not started" )
87+ return s3
88+
89+
90+ def s3_enabled () -> bool :
91+ settings = get_settings ()
92+ return all ([settings .s3_host , settings .s3_access_key , settings .s3_secret_key ])
93+
94+
7495def http () -> httpx .AsyncClient :
7596 if CONNECTIONS .http_client is None :
7697 raise ConnectionError ("HTTP client not started" )
7798 return CONNECTIONS .http_client
7899
79100
80- def s3_enabled () -> bool :
81- settings = get_settings ()
82- return all ([settings .s3_host , settings .s3_access_key , settings .s3_secret_key ])
83101
84102
85103async def _start_elastic ():
@@ -127,8 +145,6 @@ async def _start_s3() -> None:
127145 if settings .s3_access_key is None or settings .s3_secret_key is None :
128146 raise ValueError ("s3_access_key or s3_secret_key not specified" )
129147
130- ## It seems aioboto3 uses some of the sync boto3 types, so we need to hack around typing here.
131-
132148 session = get_session ()
133149 client = session .create_client (
134150 service_name = "s3" ,
@@ -138,14 +154,28 @@ async def _start_s3() -> None:
138154 config = AioConfig (signature_version = "s3v4" ),
139155 )
140156
157+ # If the s3 server is hosted directly with docker compose, fastapi needs to
158+ # use a client with the internal s3_host, but presigned requests need to be created
159+ # for the /s3 proxy.
160+ proxy_url = settings .host + '/s3' if settings .s3_use_proxy else settings .s3_host
161+ proxy_client = session .create_client (
162+ service_name = "s3" ,
163+ endpoint_url = proxy_url ,
164+ aws_access_key_id = settings .s3_access_key ,
165+ aws_secret_access_key = settings .s3_secret_key ,
166+ config = AioConfig (signature_version = "s3v4" ),
167+ )
168+
141169 CONNECTIONS .s3_context_stack = AsyncExitStack ()
142170 CONNECTIONS .s3_client = await CONNECTIONS .s3_context_stack .enter_async_context (client )
171+ CONNECTIONS .s3_proxy_client = await CONNECTIONS .s3_context_stack .enter_async_context (proxy_client )
143172
144173
145174async def _close_s3 ():
146175 if CONNECTIONS .s3_context_stack is not None :
147176 await CONNECTIONS .s3_context_stack .aclose ()
148177 CONNECTIONS .s3_client = None
178+ CONNECTIONS .s3_proxy_client = None
149179 CONNECTIONS .s3_context_stack = None
150180
151181
0 commit comments