Fix upload pause/cancel
This commit is contained in:
parent
cdb79d11aa
commit
d1e42a72a0
1
TODO.md
1
TODO.md
|
@ -50,7 +50,6 @@
|
|||
by switching to another room and coming back
|
||||
- First sent message in E2E room is sometimes undecryptable
|
||||
|
||||
- Pause upload, switch to other room, then come back → wrong state displayed
|
||||
- Pausing uploads doesn't work well, servers end up dropping the connection
|
||||
|
||||
- In the "Leave me" room, "join > Hi > left" aren't combined
|
||||
|
|
|
@ -112,8 +112,11 @@ class MatrixClient(nio.AsyncClient):
|
|||
self.profile_task: Optional[asyncio.Future] = None
|
||||
self.sync_task: Optional[asyncio.Future] = None
|
||||
self.load_rooms_task: Optional[asyncio.Future] = None
|
||||
self.first_sync_done: asyncio.Event = asyncio.Event()
|
||||
self.first_sync_date: Optional[datetime] = None
|
||||
|
||||
self.upload_monitors: Dict[UUID, nio.TransferMonitor] = {}
|
||||
|
||||
self.first_sync_done: asyncio.Event = asyncio.Event()
|
||||
self.first_sync_date: Optional[datetime] = None
|
||||
|
||||
self.past_tokens: Dict[str, str] = {} # {room_id: token}
|
||||
self.fully_loaded_rooms: Set[str] = set() # {room_id}
|
||||
|
@ -276,6 +279,25 @@ class MatrixClient(nio.AsyncClient):
|
|||
await self._send_message(room_id, content)
|
||||
|
||||
|
||||
async def toggle_pause_upload(
|
||||
self, room_id: str, uuid: Union[str, UUID],
|
||||
) -> None:
|
||||
if isinstance(uuid, str):
|
||||
uuid = UUID(uuid)
|
||||
|
||||
pause = not self.upload_monitors[uuid].pause
|
||||
|
||||
self.upload_monitors[uuid].pause = pause
|
||||
self.models[room_id, "uploads"][str(uuid)].paused = pause
|
||||
|
||||
|
||||
async def cancel_upload(self, uuid: Union[str, UUID]) -> None:
|
||||
if isinstance(uuid, str):
|
||||
uuid = UUID(uuid)
|
||||
|
||||
self.upload_monitors[uuid].cancel = True
|
||||
|
||||
|
||||
async def send_file(self, room_id: str, path: Union[Path, str]) -> None:
|
||||
"""Send a `m.file`, `m.image`, `m.audio` or `m.video` message."""
|
||||
|
||||
|
@ -285,6 +307,7 @@ class MatrixClient(nio.AsyncClient):
|
|||
await self._send_file(item_uuid, room_id, path)
|
||||
except (nio.TransferCancelledError, asyncio.CancelledError):
|
||||
log.info("Deleting item for cancelled upload %s", item_uuid)
|
||||
del self.upload_monitors[item_uuid]
|
||||
del self.models[room_id, "uploads"][str(item_uuid)]
|
||||
|
||||
|
||||
|
@ -306,9 +329,10 @@ class MatrixClient(nio.AsyncClient):
|
|||
# This error will be caught again by the try block later below
|
||||
size = 0
|
||||
|
||||
task = asyncio.Task.current_task()
|
||||
monitor = nio.TransferMonitor(size)
|
||||
upload_item = Upload(item_uuid, task, monitor, path, total_size=size)
|
||||
upload_item = Upload(item_uuid, path, total_size=size)
|
||||
|
||||
self.upload_monitors[item_uuid] = monitor
|
||||
self.models[room_id, "uploads"][str(item_uuid)] = upload_item
|
||||
|
||||
def on_transferred(transferred: int) -> None:
|
||||
|
@ -325,8 +349,14 @@ class MatrixClient(nio.AsyncClient):
|
|||
url, mime, crypt_dict = await self.upload(
|
||||
lambda *_: path,
|
||||
filename = path.name,
|
||||
encrypt = encrypt, monitor=monitor,
|
||||
encrypt = encrypt,
|
||||
monitor = monitor,
|
||||
)
|
||||
|
||||
# FIXME: nio might not catch the cancel in time
|
||||
if monitor.cancel:
|
||||
raise nio.TransferCancelledError()
|
||||
|
||||
except (MatrixError, OSError) as err:
|
||||
upload_item.status = UploadStatus.Error
|
||||
upload_item.error = type(err)
|
||||
|
@ -388,12 +418,21 @@ class MatrixClient(nio.AsyncClient):
|
|||
upload_item.total_size = len(thumb_data)
|
||||
|
||||
try:
|
||||
# The total_size passed to the monitor only considers
|
||||
# the file itself, and not the thumbnail.
|
||||
monitor.on_transferred = None
|
||||
|
||||
thumb_url, _, thumb_crypt_dict = await self.upload(
|
||||
lambda *_: thumb_data,
|
||||
filename =
|
||||
f"{path.stem}_sample{''.join(path.suffixes)}",
|
||||
encrypt = encrypt,
|
||||
monitor = monitor,
|
||||
)
|
||||
|
||||
# FIXME: nio might not catch the cancel in time
|
||||
if monitor.cancel:
|
||||
raise nio.TransferCancelledError()
|
||||
except MatrixError as err:
|
||||
log.warning(f"Failed uploading thumbnail {path}: {err}")
|
||||
else:
|
||||
|
@ -451,6 +490,7 @@ class MatrixClient(nio.AsyncClient):
|
|||
content["msgtype"] = "m.file"
|
||||
content["filename"] = path.name
|
||||
|
||||
del self.upload_monitors[item_uuid]
|
||||
del self.models[room_id, "uploads"][str(upload_item.id)]
|
||||
|
||||
await self._local_echo(
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
"""`ModelItem` subclasses definitions."""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import datetime, timedelta
|
||||
|
@ -136,18 +135,17 @@ class UploadStatus(AutoStrEnum):
|
|||
|
||||
|
||||
@dataclass
|
||||
class Upload(ModelItem): # XXX
|
||||
class Upload(ModelItem):
|
||||
"""Represent a running or failed file upload operation."""
|
||||
|
||||
id: UUID = field()
|
||||
task: asyncio.Task = field()
|
||||
monitor: nio.TransferMonitor = field()
|
||||
filepath: Path = field()
|
||||
id: UUID = field()
|
||||
filepath: Path = field()
|
||||
|
||||
total_size: int = 0
|
||||
uploaded: int = 0
|
||||
speed: float = 0
|
||||
time_left: timedelta = timedelta(0)
|
||||
paused: bool = False
|
||||
|
||||
status: UploadStatus = UploadStatus.Uploading
|
||||
error: OptionalExceptionType = type(None)
|
||||
|
|
|
@ -9,13 +9,12 @@ HColumnLayout {
|
|||
id: transfer
|
||||
|
||||
|
||||
property bool paused: false
|
||||
|
||||
property int msLeft: model.time_left || 0
|
||||
property int uploaded: model.uploaded
|
||||
readonly property int speed: model.speed
|
||||
readonly property int totalSize: model.total_size
|
||||
readonly property string status: model.status
|
||||
readonly property bool paused: model.paused
|
||||
|
||||
|
||||
function cancel() {
|
||||
|
@ -23,12 +22,13 @@ HColumnLayout {
|
|||
// immediate visual feedback
|
||||
transfer.height = 0
|
||||
// Python will delete this model item on cancel
|
||||
py.call(py.getattr(model.task, "cancel"))
|
||||
py.callClientCoro(chat.userId, "cancel_upload", [model.id])
|
||||
}
|
||||
|
||||
function pause() {
|
||||
transfer.paused = ! transfer.paused
|
||||
py.setattr(model.monitor, "pause", transfer.paused)
|
||||
function toggle_pause() {
|
||||
py.callClientCoro(
|
||||
chat.userId, "toggle_pause_upload", [chat.roomId, model.id],
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
@ -139,7 +139,7 @@ HColumnLayout {
|
|||
toolTip.text: transfer.paused ?
|
||||
qsTr("Resume") : qsTr("Pause")
|
||||
|
||||
onClicked: transfer.pause()
|
||||
onClicked: transfer.toggle_pause()
|
||||
|
||||
Layout.preferredWidth:
|
||||
status === "Uploading" ?
|
||||
|
|
Loading…
Reference in New Issue
Block a user