Past events loading (with two bugs)
This commit is contained in:
parent
83694d387b
commit
ecba7c47ec
5
TODO.md
5
TODO.md
|
@ -1,6 +1,7 @@
|
||||||
- license headers
|
- license headers
|
||||||
- replace "property var" by "property <object>" where applicable
|
- replace "property var" by "property <object>" where applicable
|
||||||
- [debug mode](https://docs.python.org/3/library/asyncio-dev.html)
|
- [debug mode](https://docs.python.org/3/library/asyncio-dev.html)
|
||||||
|
- `pyotherside.atexit()`
|
||||||
|
|
||||||
ideas
|
ideas
|
||||||
(^/v) messages unread + messages still sending
|
(^/v) messages unread + messages still sending
|
||||||
|
@ -17,7 +18,9 @@ OLD
|
||||||
- Don't bake in size properties for components
|
- Don't bake in size properties for components
|
||||||
|
|
||||||
- Bug fixes
|
- Bug fixes
|
||||||
- 100% CPU usage when hitting top edge to trigger messages loading
|
- Past events loading (limit 100) freezes the GUI - need to move upsert func
|
||||||
|
to a WorkerScript
|
||||||
|
- Past events loading: text binding loop on name request
|
||||||
- `MessageDelegate.qml:63: TypeError: 'reloadPreviousItem' not a function`
|
- `MessageDelegate.qml:63: TypeError: 'reloadPreviousItem' not a function`
|
||||||
|
|
||||||
- UI
|
- UI
|
||||||
|
|
|
@ -2,7 +2,7 @@ import asyncio
|
||||||
import json
|
import json
|
||||||
import random
|
import random
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict, Optional, Tuple
|
from typing import Dict, Optional, Set, Tuple
|
||||||
|
|
||||||
from atomicfile import AtomicFile
|
from atomicfile import AtomicFile
|
||||||
|
|
||||||
|
@ -18,8 +18,12 @@ CONFIG_LOCK = asyncio.Lock()
|
||||||
class Backend:
|
class Backend:
|
||||||
def __init__(self, app: App) -> None:
|
def __init__(self, app: App) -> None:
|
||||||
self.app = app
|
self.app = app
|
||||||
|
|
||||||
self.clients: Dict[str, MatrixClient] = {}
|
self.clients: Dict[str, MatrixClient] = {}
|
||||||
|
|
||||||
|
self.past_tokens: Dict[str, str] = {} # {room_id: token}
|
||||||
|
self.fully_loaded_rooms: Set[str] = set() # {room_id}
|
||||||
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f"{type(self).__name__}(clients={self.clients!r})"
|
return f"{type(self).__name__}(clients={self.clients!r})"
|
||||||
|
|
|
@ -114,7 +114,7 @@ class MatrixClient(nio.AsyncClient):
|
||||||
response = await self.get_profile(user_id)
|
response = await self.get_profile(user_id)
|
||||||
|
|
||||||
if isinstance(response, nio.ProfileGetError):
|
if isinstance(response, nio.ProfileGetError):
|
||||||
log.warning("Error getting profile for %r: %s", user_id, response)
|
log.warning("%s: %s", user_id, response)
|
||||||
|
|
||||||
users.UserUpdated(
|
users.UserUpdated(
|
||||||
user_id = user_id,
|
user_id = user_id,
|
||||||
|
@ -124,6 +124,11 @@ class MatrixClient(nio.AsyncClient):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@property
|
||||||
|
def all_rooms(self) -> Dict[str, MatrixRoom]:
|
||||||
|
return {**self.invited_rooms, **self.rooms}
|
||||||
|
|
||||||
|
|
||||||
async def send_markdown(self, room_id: str, text: str) -> None:
|
async def send_markdown(self, room_id: str, text: str) -> None:
|
||||||
content = {
|
content = {
|
||||||
"body": text,
|
"body": text,
|
||||||
|
@ -149,6 +154,35 @@ class MatrixClient(nio.AsyncClient):
|
||||||
log.error("Failed to send message: %s", response)
|
log.error("Failed to send message: %s", response)
|
||||||
|
|
||||||
|
|
||||||
|
async def load_past_events(self, room_id: str, limit: int = 100) -> bool:
|
||||||
|
if room_id in self.backend.fully_loaded_rooms:
|
||||||
|
return False
|
||||||
|
|
||||||
|
response = await self.room_messages(
|
||||||
|
room_id = room_id,
|
||||||
|
start = self.backend.past_tokens[room_id],
|
||||||
|
limit = limit,
|
||||||
|
)
|
||||||
|
|
||||||
|
more_to_load = True
|
||||||
|
print(len(response.chunk))
|
||||||
|
|
||||||
|
if self.backend.past_tokens[room_id] == response.end:
|
||||||
|
self.backend.fully_loaded_rooms.add(room_id)
|
||||||
|
more_to_load = False
|
||||||
|
|
||||||
|
self.backend.past_tokens[room_id] = response.end
|
||||||
|
|
||||||
|
for event in response.chunk:
|
||||||
|
for cb in self.event_callbacks:
|
||||||
|
if (cb.filter is None or isinstance(event, cb.filter)):
|
||||||
|
await cb.func(
|
||||||
|
self.all_rooms[room_id], event, from_past=True
|
||||||
|
)
|
||||||
|
|
||||||
|
return more_to_load
|
||||||
|
|
||||||
|
|
||||||
# Callbacks for nio responses
|
# Callbacks for nio responses
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -176,9 +210,12 @@ class MatrixClient(nio.AsyncClient):
|
||||||
inviter = room.inviter or "",
|
inviter = room.inviter or "",
|
||||||
)
|
)
|
||||||
|
|
||||||
for room_id, _ in resp.rooms.join.items():
|
for room_id, info in resp.rooms.join.items():
|
||||||
room = self.rooms[room_id]
|
room = self.rooms[room_id]
|
||||||
|
|
||||||
|
if room_id not in self.backend.past_tokens:
|
||||||
|
self.backend.past_tokens[room_id] = info.timeline.prev_batch
|
||||||
|
|
||||||
rooms.RoomUpdated(
|
rooms.RoomUpdated(
|
||||||
user_id = self.user_id,
|
user_id = self.user_id,
|
||||||
category = "Rooms",
|
category = "Rooms",
|
||||||
|
@ -208,7 +245,9 @@ class MatrixClient(nio.AsyncClient):
|
||||||
# %S = sender's displayname
|
# %S = sender's displayname
|
||||||
# %T = target (ev.state_key)'s displayname
|
# %T = target (ev.state_key)'s displayname
|
||||||
|
|
||||||
async def onRoomMessageText(self, room, ev) -> None:
|
# pylint: disable=unused-argument
|
||||||
|
|
||||||
|
async def onRoomMessageText(self, room, ev, from_past=False) -> None:
|
||||||
co = HTML_FILTER.filter(
|
co = HTML_FILTER.filter(
|
||||||
ev.formatted_body
|
ev.formatted_body
|
||||||
if ev.format == "org.matrix.custom.html" else html.escape(ev.body)
|
if ev.format == "org.matrix.custom.html" else html.escape(ev.body)
|
||||||
|
@ -217,26 +256,27 @@ class MatrixClient(nio.AsyncClient):
|
||||||
TimelineMessageReceived.from_nio(room, ev, content=co)
|
TimelineMessageReceived.from_nio(room, ev, content=co)
|
||||||
|
|
||||||
|
|
||||||
async def onRoomCreateEvent(self, room, ev) -> None:
|
async def onRoomCreateEvent(self, room, ev, from_past=False) -> None:
|
||||||
co = "%S allowed users on other matrix servers to join this room." \
|
co = "%S allowed users on other matrix servers to join this room." \
|
||||||
if ev.federate else \
|
if ev.federate else \
|
||||||
"%S blocked users on other matrix servers from joining this room."
|
"%S blocked users on other matrix servers from joining this room."
|
||||||
TimelineEventReceived.from_nio(room, ev, content=co)
|
TimelineEventReceived.from_nio(room, ev, content=co)
|
||||||
|
|
||||||
|
|
||||||
async def onRoomGuestAccessEvent(self, room, ev) -> None:
|
async def onRoomGuestAccessEvent(self, room, ev, from_past=False) -> None:
|
||||||
allowed = "allowed" if ev.guest_access else "forbad"
|
allowed = "allowed" if ev.guest_access else "forbad"
|
||||||
co = f"%S {allowed} guests to join the room."
|
co = f"%S {allowed} guests to join the room."
|
||||||
TimelineEventReceived.from_nio(room, ev, content=co)
|
TimelineEventReceived.from_nio(room, ev, content=co)
|
||||||
|
|
||||||
|
|
||||||
async def onRoomJoinRulesEvent(self, room, ev) -> None:
|
async def onRoomJoinRulesEvent(self, room, ev, from_past=False) -> None:
|
||||||
access = "public" if ev.join_rule == "public" else "invite-only"
|
access = "public" if ev.join_rule == "public" else "invite-only"
|
||||||
co = f"%S made the room {access}."
|
co = f"%S made the room {access}."
|
||||||
TimelineEventReceived.from_nio(room, ev, content=co)
|
TimelineEventReceived.from_nio(room, ev, content=co)
|
||||||
|
|
||||||
|
|
||||||
async def onRoomHistoryVisibilityEvent(self, room, ev) -> None:
|
async def onRoomHistoryVisibilityEvent(self, room, ev, from_past=False
|
||||||
|
) -> None:
|
||||||
if ev.history_visibility == "shared":
|
if ev.history_visibility == "shared":
|
||||||
to = "all room members"
|
to = "all room members"
|
||||||
elif ev.history_visibility == "world_readable":
|
elif ev.history_visibility == "world_readable":
|
||||||
|
@ -254,7 +294,7 @@ class MatrixClient(nio.AsyncClient):
|
||||||
TimelineEventReceived.from_nio(room, ev, content=co)
|
TimelineEventReceived.from_nio(room, ev, content=co)
|
||||||
|
|
||||||
|
|
||||||
async def onPowerLevelsEvent(self, room, ev) -> None:
|
async def onPowerLevelsEvent(self, room, ev, from_past=False) -> None:
|
||||||
co = "%S changed the room's permissions." # TODO: improve
|
co = "%S changed the room's permissions." # TODO: improve
|
||||||
TimelineEventReceived.from_nio(room, ev, content=co)
|
TimelineEventReceived.from_nio(room, ev, content=co)
|
||||||
|
|
||||||
|
@ -322,9 +362,8 @@ class MatrixClient(nio.AsyncClient):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
async def onRoomMemberEvent(self, room, ev) -> None:
|
async def onRoomMemberEvent(self, room, ev, from_past=False) -> None:
|
||||||
# TODO: ignore for past events
|
if not from_past and ev.content["membership"] != "leave":
|
||||||
if ev.content["membership"] != "leave":
|
|
||||||
users.UserUpdated(
|
users.UserUpdated(
|
||||||
user_id = ev.state_key,
|
user_id = ev.state_key,
|
||||||
display_name = ev.content["displayname"] or "",
|
display_name = ev.content["displayname"] or "",
|
||||||
|
@ -338,40 +377,40 @@ class MatrixClient(nio.AsyncClient):
|
||||||
TimelineEventReceived.from_nio(room, ev, content=co)
|
TimelineEventReceived.from_nio(room, ev, content=co)
|
||||||
|
|
||||||
|
|
||||||
async def onRoomAliasEvent(self, room, ev) -> None:
|
async def onRoomAliasEvent(self, room, ev, from_past=False) -> None:
|
||||||
co = f"%S set the room's main address to {ev.canonical_alias}."
|
co = f"%S set the room's main address to {ev.canonical_alias}."
|
||||||
TimelineEventReceived.from_nio(room, ev, content=co)
|
TimelineEventReceived.from_nio(room, ev, content=co)
|
||||||
|
|
||||||
|
|
||||||
async def onRoomNameEvent(self, room, ev) -> None:
|
async def onRoomNameEvent(self, room, ev, from_past=False) -> None:
|
||||||
co = f"%S changed the room's name to \"{ev.name}\"."
|
co = f"%S changed the room's name to \"{ev.name}\"."
|
||||||
TimelineEventReceived.from_nio(room, ev, content=co)
|
TimelineEventReceived.from_nio(room, ev, content=co)
|
||||||
|
|
||||||
|
|
||||||
async def onRoomTopicEvent(self, room, ev) -> None:
|
async def onRoomTopicEvent(self, room, ev, from_past=False) -> None:
|
||||||
co = f"%S changed the room's topic to \"{ev.topic}\"."
|
co = f"%S changed the room's topic to \"{ev.topic}\"."
|
||||||
TimelineEventReceived.from_nio(room, ev, content=co)
|
TimelineEventReceived.from_nio(room, ev, content=co)
|
||||||
|
|
||||||
|
|
||||||
async def onRoomEncryptionEvent(self, room, ev) -> None:
|
async def onRoomEncryptionEvent(self, room, ev, from_past=False) -> None:
|
||||||
co = f"%S turned on encryption for this room."
|
co = f"%S turned on encryption for this room."
|
||||||
TimelineEventReceived.from_nio(room, ev, content=co)
|
TimelineEventReceived.from_nio(room, ev, content=co)
|
||||||
|
|
||||||
|
|
||||||
async def onOlmEvent(self, room, ev) -> None:
|
async def onOlmEvent(self, room, ev, from_past=False) -> None:
|
||||||
co = f"%S hasn't sent your device the keys to decrypt this message."
|
co = f"%S hasn't sent your device the keys to decrypt this message."
|
||||||
TimelineEventReceived.from_nio(room, ev, content=co)
|
TimelineEventReceived.from_nio(room, ev, content=co)
|
||||||
|
|
||||||
|
|
||||||
async def onMegolmEvent(self, room, ev) -> None:
|
async def onMegolmEvent(self, room, ev, from_past=False) -> None:
|
||||||
await self.onOlmEvent(room, ev)
|
await self.onOlmEvent(room, ev, from_past=False)
|
||||||
|
|
||||||
|
|
||||||
async def onBadEvent(self, room, ev) -> None:
|
async def onBadEvent(self, room, ev, from_past=False) -> None:
|
||||||
co = f"%S sent a malformed event."
|
co = f"%S sent a malformed event."
|
||||||
TimelineEventReceived.from_nio(room, ev, content=co)
|
TimelineEventReceived.from_nio(room, ev, content=co)
|
||||||
|
|
||||||
|
|
||||||
async def onUnknownBadEvent(self, room, ev) -> None:
|
async def onUnknownBadEvent(self, room, ev, from_past=False) -> None:
|
||||||
co = f"%S sent an event this client doesn't understand."
|
co = f"%S sent an event this client doesn't understand."
|
||||||
TimelineEventReceived.from_nio(room, ev, content=co)
|
TimelineEventReceived.from_nio(room, ev, content=co)
|
||||||
|
|
|
@ -34,15 +34,23 @@ HRectangle {
|
||||||
// reloaded from network.
|
// reloaded from network.
|
||||||
cacheBuffer: height * 6
|
cacheBuffer: height * 6
|
||||||
|
|
||||||
// Declaring this "alias" provides the on... signal
|
// Declaring this as "alias" provides the on... signal
|
||||||
property real yPos: visibleArea.yPosition
|
property real yPos: visibleArea.yPosition
|
||||||
|
property bool canLoad: true
|
||||||
property int zz: 0
|
property int zz: 0
|
||||||
|
|
||||||
onYPosChanged: {
|
onYPosChanged: {
|
||||||
if (chatPage.category != "Invites" && yPos <= 0.1) {
|
if (chatPage.category != "Invites" && canLoad && yPos <= 0.1) {
|
||||||
zz += 1
|
zz += 1
|
||||||
print(zz)
|
print(canLoad, zz)
|
||||||
//Backend.loadPastEvents(chatPage.roomId)
|
canLoad = false
|
||||||
|
py.callClientCoro(
|
||||||
|
chatPage.userId,
|
||||||
|
"load_past_events",
|
||||||
|
[chatPage.roomId],
|
||||||
|
{},
|
||||||
|
function(more_to_load) { canLoad = more_to_load }
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,13 +86,13 @@ function onTimelineEventReceived(
|
||||||
"senderId": sender_id,
|
"senderId": sender_id,
|
||||||
"content": content,
|
"content": content,
|
||||||
"isLocalEcho": true
|
"isLocalEcho": true
|
||||||
}, 1, 500)
|
}, 1, 250)
|
||||||
|
|
||||||
if (found.length > 0) {
|
if (found.length > 0) {
|
||||||
timelines.set(found[0], item)
|
timelines.set(found[0], item)
|
||||||
} else {
|
} else {
|
||||||
// Multiple clients will emit duplicate events with the same eventId
|
// Multiple clients will emit duplicate events with the same eventId
|
||||||
timelines.upsert({"eventId": event_id}, item, true, 500)
|
timelines.upsert({"eventId": event_id}, item, true, 250)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user