Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/b2sdk api updates #19

Merged
merged 10 commits into from
Jun 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .python-version
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
3.9.0
3.9.5
3.8.6
3.7.9
3.6.12
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
run-django run-test-proj \
cleanup-docker run-sample-proj

pyversions=$(shell cat .python-version)
pyversions=$(shell cat .python-version) 3.6.12
setup:
pyenv install -s $(firstword ${pyversions})
pip install -r requirements.txt
Expand Down
47 changes: 35 additions & 12 deletions django_backblaze_b2/cache_account_info.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import logging
from functools import wraps
from hashlib import sha3_224 as hash
from typing import Iterable, Tuple
from typing import Iterable, Optional, Tuple

from b2sdk.v1 import UrlPoolAccountInfo
from b2sdk.v1.exception import MissingAccountData
from b2sdk.account_info.exception import MissingAccountData
from b2sdk.account_info.upload_url_pool import UrlPoolAccountInfo
from django.core.cache import InvalidCacheBackendError, caches
from django.core.exceptions import ImproperlyConfigured

logger = logging.getLogger(__name__)
logger = logging.getLogger("django-backblaze-b2")


class StoredBucketInfo:
Expand Down Expand Up @@ -66,26 +66,31 @@ def clear(self):
Remove all info about accounts and buckets.
"""
self.cache.clear()
self.cache.set("bucket_names", [])

def _set_auth_data(
self,
account_id,
auth_token,
api_url,
download_url,
minimum_part_size,
recommended_part_size,
absolute_minimum_part_size,
application_key,
realm,
s3_api_url,
allowed,
application_key_id,
):
self.cache.set("account_id", account_id)
self.cache.set("auth_token", auth_token)
self.cache.set("api_url", api_url)
self.cache.set("download_url", download_url)
self.cache.set("minimum_part_size", minimum_part_size)
self.cache.set("recommended_part_size", recommended_part_size)
self.cache.set("absolute_minimum_part_size", absolute_minimum_part_size)
self.cache.set("application_key", application_key)
self.cache.set("realm", realm)
self.cache.set("s3_api_url", s3_api_url)
self.cache.set("allowed", allowed)
self.cache.set("application_key_id", application_key_id)

Expand Down Expand Up @@ -121,33 +126,51 @@ def get_realm(self):
return self.cache.get("realm")

@_raise_missing_if_result_is_none
def get_minimum_part_size(self):
return self.cache.get("minimum_part_size")
def get_absolute_minimum_part_size(self):
return self.cache.get("absolute_minimum_part_size")

@_raise_missing_if_result_is_none
def get_recommended_part_size(self):
return self.cache.get("recommended_part_size")

@_raise_missing_if_result_is_none
def get_allowed(self):
return self.cache.get("allowed")

def get_bucket_id_or_none_from_bucket_name(self, bucket_name: str):
def get_s3_api_url(self):
return self.cache.get("s3_api_url") or ""

def get_bucket_id_or_none_from_bucket_name(self, bucket_name: str) -> Optional[str]:
try:
return self.cache.get(_bucket_cachekey(bucket_name))
except KeyError as e:
logger.debug(f"cache miss {bucket_name}: {e}")
return None

def get_bucket_name_or_none_from_bucket_id(self, bucket_id: str) -> Optional[str]:
try:
for bucket_name in self.cache.get("bucket_names", []):
bucket_id = self.cache.get(_bucket_cachekey(bucket_name))
if bucket_id:
return bucket_name
logger.debug(f"cache miss {bucket_id}")
except KeyError as e:
logger.debug(f"cache miss {bucket_id}: {e}")
return None

def refresh_entire_bucket_name_cache(self, name_id_iterable: Iterable[Tuple[str, str]]):
bucket_names_to_remove = set(self.cache.get("bucket_names")) - {name for name, id in name_id_iterable}
bucket_names_to_remove = set(self.cache.get("bucket_names", [])) - {name for name, id in name_id_iterable}
for (bucket_name, bucket_id) in name_id_iterable:
self.cache.set(_bucket_cachekey(bucket_name), bucket_id)
for bucket_name in bucket_names_to_remove:
self.remove_bucket_name(bucket_name)

def save_bucket(self, bucket: StoredBucketInfo):
self.cache.set(_bucket_cachekey(bucket.name), bucket.id_)
self.cache.set("bucket_names", list(self.cache.get("bucket_names")) + [bucket.name])
self.cache.set("bucket_names", list(self.cache.get("bucket_names", [])) + [bucket.name])

def remove_bucket_name(self, bucket_name):
self.cache.set("bucket_names", [n for n in self.cache.get("bucket_names") if n != bucket_name])
self.cache.set("bucket_names", [n for n in self.cache.get("bucket_names", []) if n != bucket_name])
self.cache.delete(_bucket_cachekey(bucket_name))

def __repr__(self) -> str:
Expand Down
13 changes: 8 additions & 5 deletions django_backblaze_b2/storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
from logging import getLogger
from typing import IO, Any, Callable, Dict, List, Optional, Tuple, cast

from b2sdk.account_info import InMemoryAccountInfo
from b2sdk.account_info.abstract import AbstractAccountInfo
from b2sdk.account_info.sqlite_account_info import SqliteAccountInfo
from b2sdk.api import B2Api, Bucket
from b2sdk.cache import AuthInfoCache
from b2sdk.exception import FileOrBucketNotFound
from b2sdk.v1 import B2Api, Bucket, InMemoryAccountInfo, SqliteAccountInfo
from b2sdk.v1.exception import NonExistentBucket
from b2sdk.exception import FileOrBucketNotFound, NonExistentBucket
from django.core.cache.backends.base import BaseCache
from django.core.exceptions import ImproperlyConfigured
from django.core.files.base import File
Expand Down Expand Up @@ -52,7 +53,9 @@ def __init__(self, **kwargs):
if "opts" in kwargs:
self._validateOptions(kwargs.get("opts"))
_merge(opts, kwargs.get("opts", {}))
logger.debug(f"Initializing {self.__class__.__name__} with options {opts}")
logOpts = opts.copy()
logOpts.update({"application_key_id": "<redacted>", "application_key": "<redacted>"})
logger.debug(f"Initializing {self.__class__.__name__} with options {logOpts}")

self._bucketName = opts["bucket"]
self._defaultFileMetadata = opts["defaultFileInfo"]
Expand Down Expand Up @@ -184,7 +187,7 @@ def loadInfo():
return self.bucket.get_file_info_by_name(name).as_dict()

return self._cache.get_or_set(key=cacheKey, default=loadInfo, timeout=timeoutInSeconds)
return self.bucket.get_file_info_by_name(name)
return self.bucket.get_file_info_by_name(name).as_dict()
except FileOrBucketNotFound:
return None

Expand Down
8 changes: 4 additions & 4 deletions django_backblaze_b2/storages.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ class PublicStorage(BackblazeB2Storage):

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._bucketInfo: Optional[bool] = None
self._bucketType: Optional[bool] = None
self._cdnConfig: Optional[CDNConfig] = kwargs.get("opts", {}).get("cdnConfig")

def _isPublicBucket(self) -> bool:
if self._bucketInfo is None:
self._bucketInfo = self.bucket.as_dict().get("bucketType") == "allPublic"
return self._bucketInfo
if self._bucketType is None:
self._bucketType = self.bucket.as_dict().get("bucketType") == "allPublic"
return self._bucketType

def _getFileUrl(self, name: str) -> str:
if not self._isPublicBucket():
Expand Down
Loading