Handle upload errors
This commit is contained in:
parent
08694388dd
commit
e4aa3b6572
2
TODO.md
2
TODO.md
|
@ -57,6 +57,7 @@
|
||||||
- Quote links color in room subtitles (e.g. "> http://foo.orgA)" )
|
- Quote links color in room subtitles (e.g. "> http://foo.orgA)" )
|
||||||
|
|
||||||
- UI
|
- UI
|
||||||
|
- Standardize usage of punctuation
|
||||||
- Way to open context menus without a right mouse button
|
- Way to open context menus without a right mouse button
|
||||||
- `smartVerticalFlick()` gradual acceleration
|
- `smartVerticalFlick()` gradual acceleration
|
||||||
|
|
||||||
|
@ -184,6 +185,7 @@
|
||||||
- Live-reloading accounts.json
|
- Live-reloading accounts.json
|
||||||
|
|
||||||
- nio
|
- nio
|
||||||
|
- Dedicated error for invalid password on key import
|
||||||
- Running blocking DB function calls in executor
|
- Running blocking DB function calls in executor
|
||||||
- `AsyncClient.share_group_session`: send device batches concurrently
|
- `AsyncClient.share_group_session`: send device batches concurrently
|
||||||
|
|
||||||
|
|
|
@ -220,9 +220,15 @@ class MatrixClient(nio.AsyncClient):
|
||||||
upload_item = Upload(path, total_size=size)
|
upload_item = Upload(path, total_size=size)
|
||||||
self.models[Upload, room_id][upload_item.uuid] = upload_item
|
self.models[Upload, room_id][upload_item.uuid] = upload_item
|
||||||
|
|
||||||
url, mime, crypt_dict = await self.upload(
|
try:
|
||||||
path, filename=path.name, encrypt=encrypt,
|
url, mime, crypt_dict = await self.upload(
|
||||||
)
|
path, filename=path.name, encrypt=encrypt,
|
||||||
|
)
|
||||||
|
except MatrixError as err:
|
||||||
|
upload_item.status = UploadStatus.Error
|
||||||
|
upload_item.error = type(err)
|
||||||
|
upload_item.error_args = err.args
|
||||||
|
return
|
||||||
|
|
||||||
upload_item.status = UploadStatus.Caching
|
upload_item.status = UploadStatus.Caching
|
||||||
await Media.from_existing_file(self.backend.media_cache, url, path)
|
await Media.from_existing_file(self.backend.media_cache, url, path)
|
||||||
|
@ -269,30 +275,35 @@ class MatrixClient(nio.AsyncClient):
|
||||||
else:
|
else:
|
||||||
upload_item.status = UploadStatus.UploadingThumbnail
|
upload_item.status = UploadStatus.UploadingThumbnail
|
||||||
|
|
||||||
thumb_url, _, thumb_crypt_dict = await self.upload(
|
try:
|
||||||
thumb_data,
|
thumb_url, _, thumb_crypt_dict = await self.upload(
|
||||||
filename = f"{path.stem}_sample{''.join(path.suffixes)}",
|
thumb_data,
|
||||||
encrypt = encrypt,
|
filename =
|
||||||
)
|
f"{path.stem}_sample{''.join(path.suffixes)}",
|
||||||
|
encrypt = encrypt,
|
||||||
upload_item.status = UploadStatus.CachingThumbnail
|
)
|
||||||
|
except MatrixError as err:
|
||||||
await Thumbnail.from_bytes(
|
log.warning(f"Failed uploading thumbnail {path}: {err}")
|
||||||
self.backend.media_cache,
|
|
||||||
thumb_url,
|
|
||||||
thumb_data,
|
|
||||||
wanted_size = (content["info"]["w"], content["info"]["h"]),
|
|
||||||
)
|
|
||||||
|
|
||||||
if encrypt:
|
|
||||||
content["info"]["thumbnail_file"] = {
|
|
||||||
"url": thumb_url,
|
|
||||||
**thumb_crypt_dict,
|
|
||||||
}
|
|
||||||
else:
|
else:
|
||||||
content["info"]["thumbnail_url"] = thumb_url
|
upload_item.status = UploadStatus.CachingThumbnail
|
||||||
|
|
||||||
content["info"]["thumbnail_info"] = thumb_info._asdict()
|
await Thumbnail.from_bytes(
|
||||||
|
self.backend.media_cache,
|
||||||
|
thumb_url,
|
||||||
|
thumb_data,
|
||||||
|
wanted_size = (content["info"]["w"],
|
||||||
|
content["info"]["h"]),
|
||||||
|
)
|
||||||
|
|
||||||
|
if encrypt:
|
||||||
|
content["info"]["thumbnail_file"] = {
|
||||||
|
"url": thumb_url,
|
||||||
|
**thumb_crypt_dict,
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
content["info"]["thumbnail_url"] = thumb_url
|
||||||
|
|
||||||
|
content["info"]["thumbnail_info"] = thumb_info._asdict()
|
||||||
|
|
||||||
elif kind == "audio":
|
elif kind == "audio":
|
||||||
event_type = \
|
event_type = \
|
||||||
|
|
|
@ -2,7 +2,7 @@ import re
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict, List, Optional, Type
|
from typing import Any, Dict, List, Optional, Tuple, Type, Union
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
|
||||||
import lxml # nosec
|
import lxml # nosec
|
||||||
|
@ -13,6 +13,8 @@ from ..html_filter import HTML_FILTER
|
||||||
from ..utils import AutoStrEnum, auto
|
from ..utils import AutoStrEnum, auto
|
||||||
from .model_item import ModelItem
|
from .model_item import ModelItem
|
||||||
|
|
||||||
|
OptionalExceptionType = Union[Type[None], Type[Exception]]
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Account(ModelItem):
|
class Account(ModelItem):
|
||||||
|
@ -106,15 +108,17 @@ class UploadStatus(AutoStrEnum):
|
||||||
Caching = auto()
|
Caching = auto()
|
||||||
UploadingThumbnail = auto()
|
UploadingThumbnail = auto()
|
||||||
CachingThumbnail = auto()
|
CachingThumbnail = auto()
|
||||||
Failure = auto()
|
Error = auto()
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Upload(ModelItem):
|
class Upload(ModelItem):
|
||||||
filepath: Path = field()
|
filepath: Path = field()
|
||||||
status: UploadStatus = UploadStatus.Uploading
|
status: UploadStatus = UploadStatus.Uploading
|
||||||
total_size: int = 0
|
total_size: int = 0
|
||||||
uploaded: int = 0
|
uploaded: int = 0
|
||||||
|
error: OptionalExceptionType = type(None)
|
||||||
|
error_args: Tuple[Any, ...] = ()
|
||||||
|
|
||||||
uuid: str = field(init=False, default_factory=lambda: str(uuid4()))
|
uuid: str = field(init=False, default_factory=lambda: str(uuid4()))
|
||||||
start_date: datetime = field(init=False, default_factory=datetime.now)
|
start_date: datetime = field(init=False, default_factory=datetime.now)
|
||||||
|
|
|
@ -39,6 +39,10 @@ Rectangle {
|
||||||
HLabel {
|
HLabel {
|
||||||
id: filenameLabel
|
id: filenameLabel
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
|
|
||||||
|
color: model.status === "Error" ?
|
||||||
|
theme.colors.errorText : theme.colors.text
|
||||||
|
|
||||||
text:
|
text:
|
||||||
model.status === "Uploading" ?
|
model.status === "Uploading" ?
|
||||||
qsTr("Uploading %1...").arg(fileName) :
|
qsTr("Uploading %1...").arg(fileName) :
|
||||||
|
@ -47,13 +51,25 @@ Rectangle {
|
||||||
qsTr("Caching %1...").arg(fileName) :
|
qsTr("Caching %1...").arg(fileName) :
|
||||||
|
|
||||||
model.status === "UploadingThumbnail" ?
|
model.status === "UploadingThumbnail" ?
|
||||||
qsTr("Uploading %1 thumbnail...").arg(fileName) :
|
qsTr("Uploading thumbnail for %1...").arg(fileName) :
|
||||||
|
|
||||||
model.status === "CachingThumbnail" ?
|
model.status === "CachingThumbnail" ?
|
||||||
qsTr("Caching %1 thumbnail...").arg(fileName) :
|
qsTr("Caching thumbnail for %1...").arg(fileName) :
|
||||||
|
|
||||||
model.status === "Failure" ?
|
model.status === "Error" ? (
|
||||||
qsTr("Uploading %1 failed").arg(fileName) :
|
model.error === "MatrixForbidden" ?
|
||||||
|
qsTr("Forbidden file type or quota exceeded: %1")
|
||||||
|
.arg(fileName) :
|
||||||
|
|
||||||
|
model.error === "MatrixTooLarge" ?
|
||||||
|
qsTr("Too large for this server: %1")
|
||||||
|
.arg(fileName) :
|
||||||
|
|
||||||
|
qsTr("Unknown error for %1: %2 - %3")
|
||||||
|
.arg(fileName)
|
||||||
|
.arg(model.error)
|
||||||
|
.arg(model.error_args)
|
||||||
|
) :
|
||||||
|
|
||||||
qsTr("Invalid status for %1: %2")
|
qsTr("Invalid status for %1: %2")
|
||||||
.arg(fileName).arg(model.status)
|
.arg(fileName).arg(model.status)
|
||||||
|
@ -91,8 +107,18 @@ Rectangle {
|
||||||
|
|
||||||
HProgressBar {
|
HProgressBar {
|
||||||
id: progressBar
|
id: progressBar
|
||||||
|
visible: Layout.maximumHeight !== 0
|
||||||
indeterminate: true
|
indeterminate: true
|
||||||
|
foregroundColor:
|
||||||
|
model.status === "Error" ?
|
||||||
|
theme.controls.progressBar.errorForeground :
|
||||||
|
theme.controls.progressBar.foreground
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
Layout.maximumHeight:
|
||||||
|
model.status === "Error" && indeterminate ? 0 : -1
|
||||||
|
|
||||||
|
Behavior on Layout.maximumHeight { HNumberAnimation {} }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -183,14 +183,16 @@ controls:
|
||||||
int borderWidth: 2
|
int borderWidth: 2
|
||||||
|
|
||||||
progressBar:
|
progressBar:
|
||||||
int height: Math.max(2, spacing / 2)
|
int height: Math.max(2, spacing / 2)
|
||||||
color background: colors.inputBackground
|
color background: colors.inputBackground
|
||||||
color foreground: colors.accentBackground
|
color foreground: colors.accentBackground
|
||||||
|
color errorForeground: colors.negativeBackground
|
||||||
|
|
||||||
circleProgressBar:
|
circleProgressBar:
|
||||||
int thickness: Math.max(2, spacing / 2)
|
int thickness: Math.max(2, spacing / 2)
|
||||||
color background: colors.inputBackground
|
color background: colors.inputBackground
|
||||||
color foreground: colors.accentBackground
|
color foreground: colors.accentBackground
|
||||||
|
color errorForeground: colors.negativeBackground
|
||||||
color text: colors.text
|
color text: colors.text
|
||||||
real indeterminateSpan: 0.5 // 0-1
|
real indeterminateSpan: 0.5 // 0-1
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user