MCPcopy Create free account
hub / github.com/vastsa/FileCodeBox / S3FileStorage

Class S3FileStorage

core/storage.py:260–563  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

258
259
260class S3FileStorage(FileStorageInterface):
261 def __init__(self):
262 self.access_key_id = settings.s3_access_key_id
263 self.secret_access_key = settings.s3_secret_access_key
264 self.bucket_name = settings.s3_bucket_name
265 self.s3_hostname = settings.s3_hostname
266 self.region_name = settings.s3_region_name
267 self.signature_version = settings.s3_signature_version
268 self.endpoint_url = settings.s3_endpoint_url or f"https://{self.s3_hostname}"
269 self.aws_session_token = settings.aws_session_token
270 self.addressing_style = str(settings.s3_addressing_style or "auto").lower()
271 self.proxy = settings.s3_proxy
272 self.session = aioboto3.Session(
273 aws_access_key_id=self.access_key_id,
274 aws_secret_access_key=self.secret_access_key,
275 )
276 if not settings.s3_endpoint_url:
277 self.endpoint_url = f"https://{self.s3_hostname}"
278 else:
279 # 如果提供了 s3_endpoint_url,则优先使用它
280 self.endpoint_url = settings.s3_endpoint_url
281
282 def _client_config(self) -> Config:
283 config = {"signature_version": self.signature_version}
284 s3_config = {}
285 if self.addressing_style in {"path", "virtual", "auto"}:
286 s3_config["addressing_style"] = self.addressing_style
287 if s3_config:
288 config["s3"] = s3_config
289 return Config(**config)
290
291 def _client(self):
292 return self.session.client(
293 "s3",
294 endpoint_url=self.endpoint_url,
295 aws_session_token=self.aws_session_token,
296 region_name=self.region_name,
297 config=self._client_config(),
298 )
299
300 async def save_file(self, file: UploadFile, save_path: str):
301 async with self._client() as s3:
302 # 使用 upload_fileobj 流式上传,避免将整个文件加载到内存
303 await s3.upload_fileobj(
304 file.file,
305 self.bucket_name,
306 save_path,
307 ExtraArgs={"ContentType": file.content_type or "application/octet-stream"},
308 )
309
310 async def delete_file(self, file_code: FileCodes):
311 async with self._client() as s3:
312 await s3.delete_object(
313 Bucket=self.bucket_name, Key=await file_code.get_file_path()
314 )
315
316 async def get_file_response(self, file_code: FileCodes):
317 try:

Callers

nothing calls this directly

Calls

no outgoing calls

Tested by

no test coverage detected