Files
admins 702d080a1e New Addon
Google BK
2023-04-23 18:17:03 +07:00

447 lines
11 KiB
Python

from abc import ABC, abstractmethod
from ..const import (DRIVE_FOLDER_URL_FORMAT, ERROR_BACKUP_FOLDER_INACCESSIBLE,
ERROR_BACKUP_FOLDER_MISSING, ERROR_BAD_PASSWORD_KEY,
ERROR_CREDS_EXPIRED, ERROR_DRIVE_FULL,
ERROR_EXISTING_FOLDER, ERROR_GOOGLE_CONNECT, ERROR_GOOGLE_CRED_PROCESS,
ERROR_GOOGLE_DNS, ERROR_GOOGLE_INTERNAL,
ERROR_GOOGLE_SESSION, ERROR_GOOGLE_TIMEOUT,
ERROR_HA_DELETE_ERROR, ERROR_INVALID_CONFIG, ERROR_LOGIC,
ERROR_LOW_SPACE, ERROR_MULTIPLE_DELETES, ERROR_NO_BACKUP,
ERROR_NOT_UPLOADABLE, ERROR_PLEASE_WAIT, ERROR_PROTOCOL,
ERROR_BACKUP_IN_PROGRESS, ERROR_UPLOAD_FAILED, LOG_IN_TO_DRIVE,
SUPERVISOR_PERMISSION, ERROR_GOOGLE_UNEXPECTED, ERROR_SUPERVISOR_TIMEOUT, ERROR_SUPERVISOR_UNEXPECTED, ERROR_SUPERVISOR_FILE_SYSTEM)
def ensureKey(key, target, name):
if key not in target:
raise ProtocolError(key, name, target)
return target[key]
class KnownError(Exception, ABC):
@abstractmethod
def message(self) -> str:
pass
@abstractmethod
def code(self) -> str:
pass
def httpStatus(self) -> int:
return 500
def data(self):
return {}
def retrySoon(self):
return True
class KnownTransient(KnownError):
pass
class SimulatedError(KnownError):
def __init__(self, code=None):
self._code = code
def code(self):
return self._code
def message(self):
return "Gave code " + str(self._code)
class LogicError(KnownError):
def __init__(self, message=None):
self._message = message
def message(self):
return self._message
def code(self):
return ERROR_LOGIC
class ProtocolError(KnownError):
def __init__(self, parameter=None, object_name=None, debug_object=None):
self._parameter = parameter
self._object_name = object_name
self._debug_object = debug_object
def message(self):
if self._object_name:
return "Required key '{0}' was missing from {1}".format(self._parameter, self._object_name)
else:
return self._parameter
def code(self):
return ERROR_PROTOCOL
class BackupInProgress(KnownError):
def message(self):
return "A backup is already in progress"
def code(self):
return ERROR_BACKUP_IN_PROGRESS
class BackupPasswordKeyInvalid(KnownError):
def message(self):
return "Couldn't find your backup password in your secrets file. Please check your settings."
def code(self):
return ERROR_BAD_PASSWORD_KEY
def retrySoon(self):
return False
class UploadFailed(KnownError):
def message(self):
return "Backup upload failed. Please check the supervisor logs for details."
def code(self):
return ERROR_UPLOAD_FAILED
class GoogleCredentialsExpired(KnownError):
def message(self):
return "Your Google Drive credentials have expired. Please reauthorize with Google Drive through the Web UI."
def code(self):
return ERROR_CREDS_EXPIRED
def retrySoon(self):
return False
class NoBackup(KnownError):
def message(self):
return "The backup doesn't exist anymore"
def code(self):
return ERROR_NO_BACKUP
class NotUploadable(KnownError):
def message(self):
return "This backup can't be uploaded to Home Assistant yet"
def code(self):
return ERROR_NOT_UPLOADABLE
class PleaseWait(KnownError):
def message(self):
return "Please wait until the sync is finished."
def code(self):
return ERROR_PLEASE_WAIT
class InvalidConfigurationValue(KnownError):
def __init__(self, key=None, current=None):
self.key = key
self.current = current
def message(self):
return "'{0}' isn't a valid value for {1}".format(str(self.current), str(self.key))
def code(self):
return ERROR_INVALID_CONFIG
# UI Handler Done and updated
class DeleteMutlipleBackupsError(KnownError):
def __init__(self, delete_sources=None):
self.delete_sources = delete_sources
def message(self):
return "The add-on has been configured to delete more than one older backups. Please confirm this by visiting the add-on's web UI or by setting the config option 'confirm_multiple_deletes'=false in your add-on configuration."
def code(self):
return ERROR_MULTIPLE_DELETES
def data(self):
return self.delete_sources
def retrySoon(self):
return False
class DriveQuotaExceeded(KnownError):
def message(self):
return "Google Drive is out of space"
def code(self):
return ERROR_DRIVE_FULL
def retrySoon(self):
return False
class GoogleDnsFailure(KnownError):
def message(self):
return "Unable to resolve host www.googleapis.com"
def code(self):
return ERROR_GOOGLE_DNS
class GoogleCantConnect(KnownError):
def message(self):
return "Unable to connect to www.googleapis.com"
def code(self):
return ERROR_GOOGLE_CONNECT
class GoogleInternalError(KnownTransient):
def message(self):
return "Google Drive returned an internal error (HTTP: 5XX)"
def code(self):
return ERROR_GOOGLE_INTERNAL
class GoogleTimeoutError(KnownError):
def message(self):
return "Timed out while trying to reach Google Drive"
def code(self):
return ERROR_GOOGLE_TIMEOUT
@classmethod
def factory(cls):
return GoogleTimeoutError()
class GoogleRateLimitError(KnownTransient):
def message(self):
return "The addon has made too many requests to Google Drive, and will back off"
def code(self):
return "google_rate_limit"
class GoogleSessionError(KnownError):
def message(self):
return "Upload session with Google Drive expired. The upload could not complete."
def code(self):
return ERROR_GOOGLE_SESSION
class HomeAssistantDeleteError(KnownError):
def message(self):
return "Home Assistant refused to delete the backup."
def code(self):
return ERROR_HA_DELETE_ERROR
class ExistingBackupFolderError(KnownError):
def __init__(self, existing_id: str = None, existing_name: str = None):
self.existing_id = existing_id
self.existing_name = existing_name
def message(self):
return "A backup folder already exists. Please visit the add-on Web UI to select where to backup."
def code(self):
return ERROR_EXISTING_FOLDER
def data(self):
return {
"existing_url#href": DRIVE_FOLDER_URL_FORMAT.format(self.existing_id),
"existing_name": self.existing_name
}
def retrySoon(self):
return False
class BackupFolderMissingError(KnownError):
def message(self):
return "Please visit the add-on Web UI to select where to backup."
def code(self):
return ERROR_BACKUP_FOLDER_MISSING
def retrySoon(self):
return False
class BackupFolderInaccessible(KnownError):
def __init__(self, existing_id: str = None):
self.existing_id = existing_id
def message(self):
return "The choosen backup folder has become inaccessible. Please visit the addon web UI to select a backup folder."
def data(self):
return {
"existing_url#href": DRIVE_FOLDER_URL_FORMAT.format(self.existing_id)
}
def code(self):
return ERROR_BACKUP_FOLDER_INACCESSIBLE
class GoogleDrivePermissionDenied(KnownError):
def message(self):
return "Google Drive denied the request due to permissions."
def code(self):
return "google_drive_permissions"
class LowSpaceError(KnownError):
def __init__(self, pct_used=None, space_remaining=None):
self.pct_used = pct_used
self.space_remaining = space_remaining
def message(self):
return "Your backup folder is low on disk space. Backups can't be created until space is available."
def code(self):
return ERROR_LOW_SPACE
def data(self):
return {
"pct_used": self.pct_used,
"space_remaining": self.space_remaining
}
class SupervisorConnectionError(KnownError):
def message(self):
return "The addon couldn't connect to the supervisor. Backups can't continue until the supervisor is responding."
def code(self):
return "supervisor_connection"
class UserCancelledError(KnownError):
def message(self):
return "Sync was cancelled by you"
def code(self):
return "cancelled"
def retrySoon(self):
return False
class CredRefreshGoogleError(KnownError):
def __init__(self, from_google=None):
self.from_google = from_google
def message(self):
return "Couldn't refresh your credentials with Google because: '{}'".format(self.from_google)
def code(self):
return "token_refresh_google_error"
def data(self):
return {
"from_google": self.from_google
}
class CredRefreshMyError(KnownError):
def __init__(self, reason: str = None):
self.reason = reason
def message(self):
return "Couldn't refresh Google Drive credentials because: {}".format(self.reason)
def code(self):
return "token_refresh_my_error"
def data(self):
return {
"reason": self.reason
}
class LogInToGoogleDriveError(KnownError):
def message(self):
return "Please visit drive.google.com to activate your Google Drive account."
def code(self):
return LOG_IN_TO_DRIVE
def retrySoon(self):
return False
class SupervisorPermissionError(KnownError):
def message(self):
return "The supervisor is rejecting requests from the addon. Please visit the web-UI for guidance"
def code(self):
return SUPERVISOR_PERMISSION
def retrySoon(self):
return True
class GoogleUnexpectedError(KnownError):
def message(self):
return "Google gave an unexpected response"
def code(self):
return ERROR_GOOGLE_UNEXPECTED
@classmethod
def factory(cls):
return GoogleUnexpectedError()
class SupervisorTimeoutError(KnownError):
def message(self):
return "A request to the supervisor timed out"
def code(self):
return ERROR_SUPERVISOR_TIMEOUT
@classmethod
def factory(cls):
return SupervisorTimeoutError()
class SupervisorUnexpectedError(KnownError):
def message(self):
return "The supervisor gave an unexpected response"
def code(self):
return ERROR_SUPERVISOR_UNEXPECTED
@classmethod
def factory(cls):
return SupervisorUnexpectedError()
class SupervisorFileSystemError(KnownError):
def message(self):
return "The host file system is read-only. Please restart Home Assistant and verify you have enough free space."
def code(self):
return ERROR_SUPERVISOR_FILE_SYSTEM
class GoogleCredGenerateError(KnownError):
def __init__(self, message):
self._msg = message
def message(self):
return self._msg
def code(self):
return ERROR_GOOGLE_CRED_PROCESS