New Addon
Google BK
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
# flake8: noqa
|
||||
from .exceptions import GoogleCredGenerateError, SupervisorUnexpectedError, SupervisorTimeoutError, GoogleUnexpectedError, SupervisorFileSystemError, SupervisorPermissionError, LogInToGoogleDriveError, KnownTransient, GoogleInternalError, GoogleRateLimitError, CredRefreshGoogleError, CredRefreshMyError, BackupFolderInaccessible, BackupFolderMissingError, DeleteMutlipleBackupsError, DriveQuotaExceeded, ensureKey, ExistingBackupFolderError, UserCancelledError, UploadFailed, SupervisorConnectionError, BackupPasswordKeyInvalid, BackupInProgress, SimulatedError, ProtocolError, PleaseWait, NotUploadable, NoBackup, LowSpaceError, LogicError, KnownError, InvalidConfigurationValue, HomeAssistantDeleteError, GoogleTimeoutError, GoogleSessionError, GoogleInternalError, GoogleDrivePermissionDenied, GoogleDnsFailure, GoogleCredentialsExpired, GoogleCantConnect, ExistingBackupFolderError
|
||||
@@ -0,0 +1,446 @@
|
||||
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
|
||||
Reference in New Issue
Block a user