mirror of
https://github.com/zulip/zulip.git
synced 2025-10-23 04:52:12 +00:00
upload: Use URL manipulation for get_public_upload_url logic.
This is much faster than calling generate_presigned_url each time. ``` In [3]: t = time.time() ...: for i in range(250): ...: x = u.get_public_upload_url("foo") ...: print(time.time()-t) 0.0010945796966552734 ```
This commit is contained in:
committed by
Tim Abbott
parent
9f8b5e225d
commit
10c8c0e071
@@ -387,12 +387,10 @@ class S3UploadBackend(ZulipUploadBackend):
|
|||||||
self.uploads_bucket = get_bucket(settings.S3_AUTH_UPLOADS_BUCKET, self.session)
|
self.uploads_bucket = get_bucket(settings.S3_AUTH_UPLOADS_BUCKET, self.session)
|
||||||
|
|
||||||
self._boto_client = None
|
self._boto_client = None
|
||||||
|
self.public_upload_url_pattern = self.construct_public_upload_url_pattern()
|
||||||
|
|
||||||
def get_public_upload_url(
|
def construct_public_upload_url_pattern(self) -> str:
|
||||||
self,
|
# Return the pattern for public URL for a key in the S3 Avatar bucket.
|
||||||
key: str,
|
|
||||||
) -> str:
|
|
||||||
# Return the public URL for a key in the S3 Avatar bucket.
|
|
||||||
# For Amazon S3 itself, this will return the following:
|
# For Amazon S3 itself, this will return the following:
|
||||||
# f"https://{self.avatar_bucket.name}.{network_location}/{key}"
|
# f"https://{self.avatar_bucket.name}.{network_location}/{key}"
|
||||||
#
|
#
|
||||||
@@ -401,14 +399,35 @@ class S3UploadBackend(ZulipUploadBackend):
|
|||||||
# different URL format. Configuring no signature and providing
|
# different URL format. Configuring no signature and providing
|
||||||
# no access key makes `generate_presigned_url` just return the
|
# no access key makes `generate_presigned_url` just return the
|
||||||
# normal public URL for a key.
|
# normal public URL for a key.
|
||||||
return self.get_boto_client().generate_presigned_url(
|
#
|
||||||
|
# It unfortunately takes 2ms per query to call
|
||||||
|
# generate_presigned_url, even with our cached boto
|
||||||
|
# client. Since we need to potentially compute hundreds of
|
||||||
|
# avatar URLs in single `GET /messages` request, we instead
|
||||||
|
# back-compute the URL pattern here.
|
||||||
|
|
||||||
|
DUMMY_KEY = "dummy_key_ignored"
|
||||||
|
foo_url = self.get_boto_client().generate_presigned_url(
|
||||||
ClientMethod="get_object",
|
ClientMethod="get_object",
|
||||||
Params={
|
Params={
|
||||||
"Bucket": self.avatar_bucket.name,
|
"Bucket": self.avatar_bucket.name,
|
||||||
"Key": key,
|
"Key": DUMMY_KEY,
|
||||||
},
|
},
|
||||||
ExpiresIn=0,
|
ExpiresIn=0,
|
||||||
)
|
)
|
||||||
|
parsed = urllib.parse.urlparse(foo_url)
|
||||||
|
base_path = os.path.dirname(parsed.path)
|
||||||
|
|
||||||
|
url_pattern = urllib.parse.urlunparse(
|
||||||
|
parsed._replace(path=os.path.join(base_path, "{key}"))
|
||||||
|
)
|
||||||
|
return url_pattern
|
||||||
|
|
||||||
|
def get_public_upload_url(
|
||||||
|
self,
|
||||||
|
key: str,
|
||||||
|
) -> str:
|
||||||
|
return self.public_upload_url_pattern.format(key=key)
|
||||||
|
|
||||||
def get_boto_client(self) -> botocore.client.BaseClient:
|
def get_boto_client(self) -> botocore.client.BaseClient:
|
||||||
"""
|
"""
|
||||||
|
Reference in New Issue
Block a user