New Addon
Google BK
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
from aiohttp import ClientSession, ContentTypeError, ClientConnectorError, ClientTimeout, ClientResponse
|
||||
from aiohttp.client_exceptions import ServerTimeoutError, ServerDisconnectedError, ClientOSError
|
||||
from backup.exceptions import GoogleUnexpectedError, GoogleInternalError, GoogleRateLimitError, GoogleCredentialsExpired, CredRefreshGoogleError, DriveQuotaExceeded, GoogleDrivePermissionDenied, GoogleDnsFailure, GoogleCantConnect, GoogleTimeoutError
|
||||
from backup.util import Resolver
|
||||
from backup.logger import getLogger
|
||||
from backup.config import Config, Setting
|
||||
from injector import singleton, inject
|
||||
from dns.exception import DNSException
|
||||
|
||||
RATE_LIMIT_EXCEEDED = [403]
|
||||
TOO_MANY_REQUESTS = [429]
|
||||
INTERNAL_ERROR = [500, 503]
|
||||
PERMISSION_DENIED = [401]
|
||||
REQUEST_TIMEOUT = [408]
|
||||
|
||||
logger = getLogger(__name__)
|
||||
|
||||
|
||||
@singleton
|
||||
class DriveRequester():
|
||||
@inject
|
||||
def __init__(self, config: Config, session: ClientSession, resolver: Resolver):
|
||||
self.session = session
|
||||
self.resolver = resolver
|
||||
self.config = config
|
||||
|
||||
async def request(self, method, url, headers={}, json=None, data=None) -> ClientResponse:
|
||||
try:
|
||||
response = await self.session.request(method, url, headers=headers, json=json, timeout=self.buildTimeout(), data=data)
|
||||
if response.status < 400:
|
||||
return response
|
||||
await self.raiseForKnownErrors(response)
|
||||
if response.status in PERMISSION_DENIED:
|
||||
response.release()
|
||||
raise GoogleCredentialsExpired()
|
||||
elif response.status in INTERNAL_ERROR:
|
||||
response.release()
|
||||
raise GoogleInternalError()
|
||||
elif response.status in RATE_LIMIT_EXCEEDED or response.status in TOO_MANY_REQUESTS:
|
||||
response.release()
|
||||
raise GoogleRateLimitError()
|
||||
elif response.status in REQUEST_TIMEOUT:
|
||||
response.release()
|
||||
raise GoogleTimeoutError()
|
||||
response.raise_for_status()
|
||||
return response
|
||||
except ClientConnectorError as e:
|
||||
logger.debug(
|
||||
"Ran into trouble reaching Google Drive's servers. We'll use alternate DNS servers on the next attempt.")
|
||||
self.resolver.toggle()
|
||||
if "Cannot connect to host" in str(e) or "Connection reset by peer" in str(e):
|
||||
raise GoogleCantConnect()
|
||||
if e.os_error.errno == -2:
|
||||
# -2 means dns lookup failed.
|
||||
raise GoogleDnsFailure()
|
||||
elif str(e.os_error) == "Domain name not found":
|
||||
raise GoogleDnsFailure()
|
||||
elif e.os_error.errno in [99, 111, 10061, 104]:
|
||||
# 111 means connection refused
|
||||
# Can't connect
|
||||
raise GoogleCantConnect()
|
||||
elif "Could not contact DNS serve" in str(e.os_error):
|
||||
# Wish there was a better way to identify this exception
|
||||
raise GoogleDnsFailure()
|
||||
raise
|
||||
except ClientOSError as e:
|
||||
if e.errno == 1:
|
||||
raise GoogleUnexpectedError()
|
||||
raise
|
||||
except ServerTimeoutError:
|
||||
raise GoogleTimeoutError()
|
||||
except ServerDisconnectedError:
|
||||
raise GoogleUnexpectedError()
|
||||
except DNSException:
|
||||
logger.debug(
|
||||
"Ran into trouble resolving Google Drive's servers. We'll use normal DNS servers on the next attempt.")
|
||||
self.resolver.toggle()
|
||||
raise GoogleDnsFailure()
|
||||
|
||||
def buildTimeout(self):
|
||||
return ClientTimeout(
|
||||
sock_connect=self.config.get(
|
||||
Setting.GOOGLE_DRIVE_TIMEOUT_SECONDS),
|
||||
sock_read=self.config.get(Setting.GOOGLE_DRIVE_TIMEOUT_SECONDS))
|
||||
|
||||
async def raiseForKnownErrors(self, response):
|
||||
try:
|
||||
message = await response.json()
|
||||
except ContentTypeError:
|
||||
return
|
||||
except ValueError:
|
||||
# parsing json failed, just give up
|
||||
return
|
||||
except TypeError:
|
||||
# Same
|
||||
return
|
||||
if "error" not in message:
|
||||
return
|
||||
error_obj = message["error"]
|
||||
if isinstance(error_obj, str):
|
||||
if error_obj == "expired":
|
||||
raise GoogleCredentialsExpired()
|
||||
else:
|
||||
raise CredRefreshGoogleError(error_obj)
|
||||
if "errors" not in error_obj:
|
||||
return
|
||||
for error in error_obj["errors"]:
|
||||
if "reason" not in error:
|
||||
continue
|
||||
if error["reason"] == "storageQuotaExceeded":
|
||||
raise DriveQuotaExceeded()
|
||||
elif error["reason"] in ["forbidden", "insufficientFilePermissions"]:
|
||||
raise GoogleDrivePermissionDenied()
|
||||
Reference in New Issue
Block a user