Remove all Backend "get_any_client"-using methods

thumbnail() and download() were remaining.
Use a direct and carefully chosen MatrixClient's methods instead to
avoid problems mentioned in the previous commit 7502c1.
This commit is contained in:
miruka 2020-08-23 16:57:53 -04:00
parent 0f2efa9ba3
commit df3f1fb645
24 changed files with 117 additions and 129 deletions

View File

@ -1,5 +1,6 @@
# TODO # TODO
- composer state.json writingUserId problem?
- refresh server list button - refresh server list button
- global presence control - global presence control

View File

@ -349,46 +349,7 @@ class Backend:
failures += 1 failures += 1
async def get_any_client(self) -> MatrixClient: # Multi-client Matrix functions
"""Return any healthy syncing `MatrixClient` registered in model."""
failures = 0
while True:
for client in self.clients.values():
if client.healthy:
return client
if failures and failures % 300 == 0:
log.warn(
"No healthy client found after %ds, stack trace:\n%s",
failures / 10, traceback.format_stack(),
)
await asyncio.sleep(0.1)
failures += 1
# Client functions that don't need authentification
async def thumbnail(
self, server_name: str, media_id: str, width: int, height: int,
) -> nio.ThumbnailResponse:
"""Return thumbnail for a matrix media."""
args = (server_name, media_id, width, height)
client = await self.get_any_client()
return await client.thumbnail(*args)
async def download(
self, server_name: str, media_id: str,
) -> nio.DownloadResponse:
"""Return the content of a matrix media."""
client = await self.get_any_client()
return await client.download(server_name, media_id)
async def update_room_read_marker( async def update_room_read_marker(
self, room_id: str, event_id: str, self, room_id: str, event_id: str,
@ -416,6 +377,37 @@ class Backend:
await asyncio.gather(*[update(c) for c in self.clients.values()]) await asyncio.gather(*[update(c) for c in self.clients.values()])
async def verify_device(
self, user_id: str, device_id: str, ed25519_key: str,
) -> None:
"""Mark a device as verified on all our accounts."""
for client in self.clients.values():
try:
device = client.device_store[user_id][device_id]
except KeyError:
continue
if device.ed25519 == ed25519_key:
client.verify_device(device)
async def blacklist_device(
self, user_id: str, device_id: str, ed25519_key: str,
) -> None:
"""Mark a device as blacklisted on all our accounts."""
for client in self.clients.values():
try:
# This won't include the client's current device, as expected
device = client.device_store[user_id][device_id]
except KeyError:
continue
if device.ed25519 == ed25519_key:
client.blacklist_device(device)
# General functions # General functions
async def get_config_dir(self) -> Path: async def get_config_dir(self) -> Path:
@ -463,37 +455,6 @@ class Backend:
self.models["all_rooms"].set_account_collapse(user_id, collapse) self.models["all_rooms"].set_account_collapse(user_id, collapse)
async def verify_device(
self, user_id: str, device_id: str, ed25519_key: str,
) -> None:
"""Mark a device as verified on all our accounts."""
for client in self.clients.values():
try:
device = client.device_store[user_id][device_id]
except KeyError:
continue
if device.ed25519 == ed25519_key:
client.verify_device(device)
async def blacklist_device(
self, user_id: str, device_id: str, ed25519_key: str,
) -> None:
"""Mark a device as blacklisted on all our accounts."""
for client in self.clients.values():
try:
# This won't include the client's current device, as expected
device = client.device_store[user_id][device_id]
except KeyError:
continue
if device.ed25519 == ed25519_key:
client.blacklist_device(device)
async def _ping_homeserver( async def _ping_homeserver(
self, session: aiohttp.ClientSession, homeserver_url: str, self, session: aiohttp.ClientSession, homeserver_url: str,
) -> None: ) -> None:

View File

@ -210,18 +210,6 @@ class MatrixClient(nio.AsyncClient):
) )
@property
def healthy(self) -> bool:
"""Return whether we're syncing and last sync was successful."""
task = self.sync_task
if not task or not self.first_sync_date or self.last_sync_error:
return False
return not task.done()
@property @property
def default_device_name(self) -> str: def default_device_name(self) -> str:
"""Device name to set at login if the user hasn't set a custom one.""" """Device name to set at login if the user hasn't set a custom one."""
@ -734,7 +722,7 @@ class MatrixClient(nio.AsyncClient):
upload_item.status = UploadStatus.Caching upload_item.status = UploadStatus.Caching
local_media = await Media.from_existing_file( local_media = await Media.from_existing_file(
self.backend.media_cache, url, path, self.backend.media_cache, self.user_id, url, path,
) )
kind = (mime or "").split("/")[0] kind = (mime or "").split("/")[0]
@ -816,6 +804,7 @@ class MatrixClient(nio.AsyncClient):
await Thumbnail.from_bytes( await Thumbnail.from_bytes(
self.backend.media_cache, self.backend.media_cache,
self.user_id,
thumb_url, thumb_url,
path.name, path.name,
thumb_data, thumb_data,

View File

@ -49,17 +49,19 @@ class MediaCache:
async def get_media( async def get_media(
self, self,
client_user_id: str,
mxc: str, mxc: str,
title: str, title: str,
crypt_dict: CryptDict = None, crypt_dict: CryptDict = None,
) -> Path: ) -> Path:
"""Return `Media.get()`'s result. Intended for QML.""" """Return `Media.get()`'s result. Intended for QML."""
return await Media(self, mxc, title, crypt_dict).get() return await Media(self, client_user_id, mxc, title, crypt_dict).get()
async def get_thumbnail( async def get_thumbnail(
self, self,
client_user_id: str,
mxc: str, mxc: str,
title: str, title: str,
width: int, width: int,
@ -68,10 +70,10 @@ class MediaCache:
) -> Path: ) -> Path:
"""Return `Thumbnail.get()`'s result. Intended for QML.""" """Return `Thumbnail.get()`'s result. Intended for QML."""
thumb = Thumbnail(
# QML sometimes pass float sizes, which matrix API doesn't like. # QML sometimes pass float sizes, which matrix API doesn't like.
self, mxc, title, crypt_dict, (round(width), round(height)), size = (round(width), round(height))
)
thumb = Thumbnail(self, client_user_id, mxc, title, crypt_dict, size)
return await thumb.get() return await thumb.get()
@ -80,6 +82,7 @@ class Media:
"""A matrix media file.""" """A matrix media file."""
cache: "MediaCache" = field() cache: "MediaCache" = field()
client_user_id: str = field()
mxc: str = field() mxc: str = field()
title: str = field() title: str = field()
crypt_dict: CryptDict = field(repr=False) crypt_dict: CryptDict = field(repr=False)
@ -154,7 +157,7 @@ class Media:
parsed = urlparse(self.mxc) parsed = urlparse(self.mxc)
resp = await self.cache.backend.download( resp = await self.cache.backend.clients[self.client_user_id].download(
server_name = parsed.netloc, server_name = parsed.netloc,
media_id = parsed.path.lstrip("/"), media_id = parsed.path.lstrip("/"),
) )
@ -184,6 +187,7 @@ class Media:
async def from_existing_file( async def from_existing_file(
cls, cls,
cache: "MediaCache", cache: "MediaCache",
client_user_id: str,
mxc: str, mxc: str,
existing: Path, existing: Path,
overwrite: bool = False, overwrite: bool = False,
@ -191,7 +195,9 @@ class Media:
) -> "Media": ) -> "Media":
"""Copy an existing file to cache and return a `Media` for it.""" """Copy an existing file to cache and return a `Media` for it."""
media = cls(cache, mxc, existing.name, {}, **kwargs) # type: ignore media = cls(
cache, client_user_id, mxc, existing.name, {}, **kwargs,
) # type: ignore
media.local_path.parent.mkdir(parents=True, exist_ok=True) media.local_path.parent.mkdir(parents=True, exist_ok=True)
if not media.local_path.exists() or overwrite: if not media.local_path.exists() or overwrite:
@ -205,6 +211,7 @@ class Media:
async def from_bytes( async def from_bytes(
cls, cls,
cache: "MediaCache", cache: "MediaCache",
client_user_id: str,
mxc: str, mxc: str,
filename: str, filename: str,
data: bytes, data: bytes,
@ -213,7 +220,9 @@ class Media:
) -> "Media": ) -> "Media":
"""Create a cached file from bytes data and return a `Media` for it.""" """Create a cached file from bytes data and return a `Media` for it."""
media = cls(cache, mxc, filename, {}, **kwargs) # type: ignore media = cls(
cache, client_user_id, mxc, filename, {}, **kwargs,
) # type: ignore
media.local_path.parent.mkdir(parents=True, exist_ok=True) media.local_path.parent.mkdir(parents=True, exist_ok=True)
if not media.local_path.exists() or overwrite: if not media.local_path.exists() or overwrite:
@ -231,6 +240,7 @@ class Thumbnail(Media):
"""The thumbnail of a matrix media, which is a media itself.""" """The thumbnail of a matrix media, which is a media itself."""
cache: "MediaCache" = field() cache: "MediaCache" = field()
client_user_id: str = field()
mxc: str = field() mxc: str = field()
title: str = field() title: str = field()
crypt_dict: CryptDict = field(repr=False) crypt_dict: CryptDict = field(repr=False)
@ -322,16 +332,17 @@ class Thumbnail(Media):
"""Return the (decrypted) media file's content from the server.""" """Return the (decrypted) media file's content from the server."""
parsed = urlparse(self.mxc) parsed = urlparse(self.mxc)
client = self.cache.backend.clients[self.client_user_id]
if self.crypt_dict: if self.crypt_dict:
# Matrix makes encrypted thumbs only available through the download # Matrix makes encrypted thumbs only available through the download
# end-point, not the thumbnail one # end-point, not the thumbnail one
resp = await self.cache.backend.download( resp = await client.download(
server_name = parsed.netloc, server_name = parsed.netloc,
media_id = parsed.path.lstrip("/"), media_id = parsed.path.lstrip("/"),
) )
else: else:
resp = await self.cache.backend.thumbnail( resp = await client.thumbnail(
server_name = parsed.netloc, server_name = parsed.netloc,
media_id = parsed.path.lstrip("/"), media_id = parsed.path.lstrip("/"),
width = self.wanted_size[0], width = self.wanted_size[0],

View File

@ -193,6 +193,7 @@ class NioCallbacks:
try: try:
media_local_path: Union[Path, str] = await Media( media_local_path: Union[Path, str] = await Media(
cache = self.client.backend.media_cache, cache = self.client.backend.media_cache,
client_user_id = self.user_id,
mxc = ev.url, mxc = ev.url,
title = ev.body, title = ev.body,
crypt_dict = media_crypt_dict, crypt_dict = media_crypt_dict,

View File

@ -9,6 +9,7 @@ Rectangle {
property bool compact: false property bool compact: false
property string name property string name
property alias clientUserId: avatarImage.clientUserId
property alias mxc: avatarImage.mxc property alias mxc: avatarImage.mxc
property alias title: avatarImage.title property alias title: avatarImage.title
@ -60,11 +61,11 @@ Rectangle {
HMxcImage { HMxcImage {
id: avatarImage id: avatarImage
anchors.fill: parent anchors.fill: parent
showProgressBar: false
visible: Boolean(sourceOverride || mxc) visible: Boolean(sourceOverride || mxc)
z: 2 z: 2
sourceSize.width: parent.width sourceSize.width: parent.width
sourceSize.height: parent.height sourceSize.height: parent.height
showProgressBar: false
fillMode: Image.PreserveAspectCrop fillMode: Image.PreserveAspectCrop
animatedFillMode: AnimatedImage.PreserveAspectCrop animatedFillMode: AnimatedImage.PreserveAspectCrop
animate: false animate: false
@ -95,6 +96,7 @@ Rectangle {
id: avatarToolTipImage id: avatarToolTipImage
fillMode: Image.PreserveAspectCrop fillMode: Image.PreserveAspectCrop
animatedFillMode: AnimatedImage.PreserveAspectCrop animatedFillMode: AnimatedImage.PreserveAspectCrop
clientUserId: avatarImage.clientUserId
mxc: avatarImage.mxc mxc: avatarImage.mxc
title: avatarImage.title title: avatarImage.title

View File

@ -6,6 +6,7 @@ import "../PythonBridge"
HImage { HImage {
id: image id: image
property string clientUserId
property string mxc property string mxc
property string title property string title
property string sourceOverride: "" property string sourceOverride: ""
@ -38,9 +39,10 @@ HImage {
} }
const method = image.thumbnail ? "get_thumbnail" : "get_media" const method = image.thumbnail ? "get_thumbnail" : "get_media"
const args = image.thumbnail ? const args =
[image.mxc, image.title, w, h, cryptDict] : image.thumbnail ?
[image.mxc, image.title, cryptDict] [clientUserId, image.mxc, image.title, w, h, cryptDict] :
[clientUserId, image.mxc, image.title, cryptDict]
getFuture = py.callCoro("media_cache." + method, args, path => { getFuture = py.callCoro("media_cache." + method, args, path => {
if (! image) return if (! image) return

View File

@ -57,6 +57,7 @@ HTile {
HUserAvatar { HUserAvatar {
id: avatar id: avatar
clientUserId: model.id
userId: model.id userId: model.id
displayName: model.display_name displayName: model.display_name
mxc: model.avatar_url mxc: model.avatar_url

View File

@ -48,6 +48,7 @@ HTile {
HRoomAvatar { HRoomAvatar {
id: avatar id: avatar
clientUserId: model.for_account
roomId: model.id roomId: model.id
displayName: model.display_name displayName: model.display_name
mxc: model.avatar_url mxc: model.avatar_url

View File

@ -93,6 +93,7 @@ HFlickableColumnPage {
property bool changed: Boolean(sourceOverride) property bool changed: Boolean(sourceOverride)
clientUserId: page.userId
userId: page.userId userId: page.userId
displayName: nameField.item.text displayName: nameField.item.text
mxc: account ? account.avatar_url : "" mxc: account ? account.avatar_url : ""

View File

@ -69,6 +69,7 @@ HFlickableColumnPage {
HRoomAvatar { HRoomAvatar {
id: avatar id: avatar
clientUserId: page.userId
roomId: "" roomId: ""
displayName: nameField.item.text displayName: nameField.item.text

View File

@ -8,7 +8,7 @@ HUserAvatar {
property QtObject account property QtObject account
// userId: (set me) clientUserId: userId
displayName: account ? account.display_name : "" displayName: account ? account.display_name : ""
mxc: account ? account.avatar_url : "" mxc: account ? account.avatar_url : ""

View File

@ -16,6 +16,7 @@ HTile {
HUserAvatar { HUserAvatar {
id: avatar id: avatar
clientUserId: chat.userId
userId: model.id userId: model.id
displayName: model.display_name displayName: model.display_name
mxc: model.avatar_url mxc: model.avatar_url

View File

@ -40,6 +40,7 @@ Rectangle {
HUserAvatar { HUserAvatar {
id: bannerAvatar id: bannerAvatar
clientUserId: chat.userId
anchors.centerIn: parent anchors.centerIn: parent
radius: 0 radius: 0
} }

View File

@ -25,6 +25,7 @@ Rectangle {
HUserAvatar { HUserAvatar {
id: avatar id: avatar
radius: 0 radius: 0
clientUserId: messageArea.writingUserId
userId: messageArea.writingUserId userId: messageArea.writingUserId
mxc: mxc:

View File

@ -52,6 +52,7 @@ Rectangle {
HRoomAvatar { HRoomAvatar {
id: avatar id: avatar
clientUserId: chat.userId
roomId: chat.roomId roomId: chat.roomId
displayName: chat.roomInfo.display_name displayName: chat.roomInfo.display_name
mxc: chat.roomInfo.avatar_url mxc: chat.roomInfo.avatar_url

View File

@ -23,6 +23,7 @@ HTile {
HUserAvatar { HUserAvatar {
id: avatar id: avatar
clientUserId: chat.userId
userId: model.id userId: model.id
displayName: model.display_name displayName: model.display_name
mxc: model.avatar_url mxc: model.avatar_url

View File

@ -61,6 +61,7 @@ HListView {
root.currentIndex = 0 root.currentIndex = 0
HUserAvatar { HUserAvatar {
clientUserId: chat.userId
userId: member.id userId: member.id
displayName: member.display_name displayName: member.display_name
mxc: member.avatar_url mxc: member.avatar_url

View File

@ -82,6 +82,7 @@ HFlickableColumnPage {
HRoomAvatar { HRoomAvatar {
id: avatar id: avatar
clientUserId: chat.userId
roomId: chat.roomId roomId: chat.roomId
displayName: nameField.item.text || chat.roomInfo.display_name displayName: nameField.item.text || chat.roomInfo.display_name
mxc: chat.roomInfo.avatar_url mxc: chat.roomInfo.avatar_url

View File

@ -94,6 +94,7 @@ HRowLayout {
HUserAvatar { HUserAvatar {
id: avatar id: avatar
clientUserId: chat.userId
userId: model.sender_id userId: model.sender_id
displayName: model.sender_name displayName: model.sender_name
mxc: model.sender_avatar mxc: model.sender_avatar

View File

@ -60,6 +60,7 @@ HMxcImage {
height: fitSize.height height: fitSize.height
horizontalAlignment: Image.AlignLeft horizontalAlignment: Image.AlignLeft
clientUserId: chat.userId
title: thumbnail ? loader.thumbnailTitle : loader.title title: thumbnail ? loader.thumbnailTitle : loader.title
animated: eventList.isAnimated(loader.singleMediaInfo) animated: eventList.isAnimated(loader.singleMediaInfo)
thumbnail: ! animated && loader.thumbnailMxc thumbnail: ! animated && loader.thumbnailMxc

View File

@ -416,6 +416,7 @@ Rectangle {
window.makePopup( window.makePopup(
"Popups/ImageViewerPopup/ImageViewerPopup.qml", "Popups/ImageViewerPopup/ImageViewerPopup.qml",
{ {
clientUserId: chat.userId,
thumbnailTitle: getThumbnailTitle(event), thumbnailTitle: getThumbnailTitle(event),
thumbnailMxc: event.thumbnail_url, thumbnailMxc: event.thumbnail_url,
thumbnailPath: eventList.thumbnailCachedPaths[event.id], thumbnailPath: eventList.thumbnailCachedPaths[event.id],
@ -459,6 +460,7 @@ Rectangle {
print("Downloading " + event.media_url + " ...") print("Downloading " + event.media_url + " ...")
const args = [ const args = [
chat.userId,
event.media_url, event.media_url,
event.media_title, event.media_title,
JSON.parse(event.media_crypt_dict), JSON.parse(event.media_crypt_dict),

View File

@ -8,14 +8,18 @@ import "../../Base"
HPopup { HPopup {
id: popup id: popup
property string clientUserId
property string thumbnailTitle property string thumbnailTitle
property string thumbnailMxc property string thumbnailMxc
property string thumbnailPath: "" property string thumbnailPath: ""
property var thumbnailCryptDict property var thumbnailCryptDict
property string fullTitle property string fullTitle
property string fullMxc property string fullMxc
property var fullCryptDict property var fullCryptDict
property int fullFileSize property int fullFileSize
property size overallSize property size overallSize
property bool alternateScaling: false property bool alternateScaling: false

View File

@ -107,6 +107,7 @@ HFlickable {
Math.min(window.height, viewer.overallSize.height) Math.min(window.height, viewer.overallSize.height)
clientUserId: viewer.clientUserId
showPauseButton: false showPauseButton: false
showProgressBar: false showProgressBar: false
pause: viewer.imagesPaused pause: viewer.imagesPaused
@ -152,6 +153,7 @@ HFlickable {
HMxcImage { HMxcImage {
id: full id: full
anchors.fill: parent anchors.fill: parent
clientUserId: viewer.clientUserId
thumbnail: false thumbnail: false
showPauseButton: false showPauseButton: false
pause: viewer.imagesPaused pause: viewer.imagesPaused