Upload stats

This commit is contained in:
miruka 2019-12-05 10:00:23 -04:00
parent 3aff20006c
commit a555ad0e19
4 changed files with 57 additions and 25 deletions

View File

@ -215,8 +215,8 @@ class MatrixClient(nio.AsyncClient):
try:
await self._send_file(item_uuid, room_id, path)
except asyncio.CancelledError:
del self.models[Upload, room_id][item_uuid]
except (nio.TransferCancelledError, asyncio.CancelledError):
del self.models[Upload, room_id][str(item_uuid)]
async def _send_file(
@ -235,18 +235,27 @@ class MatrixClient(nio.AsyncClient):
task = asyncio.Task.current_task()
upload_item = Upload(item_uuid, task, path, total_size=size)
self.models[Upload, room_id][upload_item.uuid] = upload_item
self.models[Upload, room_id][str(item_uuid)] = upload_item
def on_transfered(transfered: int) -> None:
upload_item.uploaded = transfered
upload_item.time_left = monitor.remaining_time
def on_speed_change(speed: float) -> None:
upload_item.speed = speed
monitor = nio.TransferMonitor(size, on_transfered, on_speed_change)
try:
url, mime, crypt_dict = await self.upload(
path, filename=path.name, encrypt=encrypt,
path, filename=path.name, encrypt=encrypt, monitor=monitor,
)
except (MatrixError, OSError) as err:
upload_item.status = UploadStatus.Error
upload_item.error = type(err)
upload_item.error_args = err.args
# Wait for cancellation, see parent send_file() method
# Wait for cancellation from UI, see parent send_file() method
while True:
await asyncio.sleep(0.1)
@ -606,9 +615,10 @@ class MatrixClient(nio.AsyncClient):
async def upload(
self,
data: UploadData,
mime: Optional[str] = None,
filename: Optional[str] = None,
encrypt: bool = False,
mime: Optional[str] = None,
filename: Optional[str] = None,
encrypt: bool = False,
monitor: Optional[nio.TransferMonitor] = None,
) -> UploadReturn:
mime = mime or await utils.guess_mime(data)
@ -618,6 +628,7 @@ class MatrixClient(nio.AsyncClient):
"application/octet-stream" if encrypt else mime,
filename,
encrypt,
monitor,
)
if isinstance(response, nio.UploadError):

View File

@ -1,7 +1,7 @@
import asyncio
import re
from dataclasses import dataclass, field
from datetime import datetime
from datetime import datetime, timedelta
from pathlib import Path
from typing import Any, Dict, List, Optional, Tuple, Type, Union
from uuid import UUID
@ -114,12 +114,16 @@ class UploadStatus(AutoStrEnum):
@dataclass
class Upload(ModelItem):
uuid: UUID = field()
task: asyncio.Task = field()
filepath: Path = field()
uuid: UUID = field()
task: asyncio.Task = field()
filepath: Path = field()
total_size: int = 0
uploaded: int = 0
speed: float = 0
time_left: Optional[timedelta] = None
status: UploadStatus = UploadStatus.Uploading
total_size: int = 0
uploaded: int = 0
error: OptionalExceptionType = type(None)
error_args: Tuple[Any, ...] = ()

View File

@ -7,6 +7,7 @@ import inspect
import io
import logging as log
import xml.etree.cElementTree as xml_etree # FIXME: bandit warning
from datetime import timedelta
from enum import Enum
from enum import auto as autostr
from pathlib import Path
@ -140,6 +141,9 @@ def serialize_value_for_qml(value: Any) -> Any:
if isinstance(value, UUID):
return str(value)
if isinstance(value, timedelta):
return value.total_seconds() * 1000
if inspect.isclass(value):
return value.__name__

View File

@ -94,7 +94,7 @@ Rectangle {
.arg(fileName) :
model.error === "IsADirectoryError" ?
qsTr("Can't upload folders: %1")
qsTr("Can't upload folders, need a file: %1")
.arg(filePath) :
model.error === "FileNotFoundError" ?
@ -128,6 +128,13 @@ Rectangle {
readonly property string filePath:
model.filepath.replace(/^file:\/\//, "")
HoverHandler { id: statusLabelHover }
HToolTip {
text: parent.truncated ? parent.text : ""
visible: text && statusLabelHover.hovered
}
}
HSpacer {}
@ -135,7 +142,11 @@ Rectangle {
HLabel {
id: uploadCountLabel
visible: Layout.preferredWidth > 0
text: qsTr("%1")
text: qsTr("-%1 %2/s %3/%4")
.arg(model.time_left ?
Utils.formatDuration(msLeft) : "∞")
.arg(CppUtils.formattedBytes(model.speed))
.arg(CppUtils.formattedBytes(uploaded))
.arg(CppUtils.formattedBytes(model.total_size))
topPadding: theme.spacing / 2
@ -146,6 +157,12 @@ Rectangle {
Layout.preferredWidth:
model.status === "Uploading" ? implicitWidth : 0
property int msLeft: model.time_left || -1
property int uploaded: model.uploaded
Behavior on msLeft { HNumberAnimation { duration: 1000 } }
Behavior on uploaded { HNumberAnimation { duration: 1000 }}
Behavior on Layout.preferredWidth { HNumberAnimation {} }
}
@ -153,20 +170,15 @@ Rectangle {
onTapped: if (model.status !== "Error")
statusLabel.expand = ! statusLabel.expand
}
HoverHandler { id: infoRowHover }
HToolTip {
id: statusToolTip
text: statusLabel.truncated ? statusLabel.text : ""
visible: text && infoRowHover.hovered
}
}
HProgressBar {
id: progressBar
visible: Layout.maximumHeight !== 0
indeterminate: true
indeterminate: model.status !== "Uploading"
value: model.uploaded
to: model.total_size
foregroundColor:
model.status === "Error" ?
theme.controls.progressBar.errorForeground :
@ -176,6 +188,7 @@ Rectangle {
Layout.maximumHeight:
model.status === "Error" && indeterminate ? 0 : -1
Behavior on value { HNumberAnimation { duration: 1000 } }
Behavior on Layout.maximumHeight { HNumberAnimation {} }
}
}