Add local echoing of messages

As per
https://matrix.org/docs/spec/client_server/latest.html#local-echo
This commit is contained in:
miruka 2019-04-18 13:46:39 -04:00
parent e9b3628fcc
commit 11d900965a
5 changed files with 85 additions and 22 deletions

View File

@ -36,3 +36,6 @@
- nio: org.matrix.room.preview\_urls, m.room.aliases
- Markdown: don't turn #things into title (space), disable __ syntax
- ![A picture](https://picsum.photos/256/256) not clickable?
- On sync, check messages API, if a limited sync timeline was received

View File

@ -46,6 +46,7 @@ class Client(QObject):
roomPastPrevBatchTokenReceived = pyqtSignal(str, str)
roomEventReceived = pyqtSignal(str, str, dict)
roomTypingUsersUpdated = pyqtSignal(str, list)
messageAboutToBeSent = pyqtSignal(str, dict)
def __init__(self,
@ -171,7 +172,6 @@ class Client(QObject):
return
self._loading = True
print("load", limit)
self._on_past_events(
room_id,
self.net.talk(
@ -201,4 +201,11 @@ class Client(QObject):
"format": "org.matrix.custom.html",
"msgtype": "m.text",
}
self.net.talk(self.nio.room_send, room_id, "m.room.message", content)
self.messageAboutToBeSent.emit(room_id, content)
self.net.talk(
self.nio.room_send,
room_id = room_id,
message_type = "m.room.message",
content = content,
)

View File

@ -24,3 +24,4 @@ class RoomEvent(NamedTuple):
type: str
date_time: QDateTime
dict: Dict[str, str]
is_local_echo: bool = False

View File

@ -6,19 +6,22 @@ from typing import Any, Deque, Dict, List, Optional
from PyQt5.QtCore import QDateTime, QObject, pyqtBoundSignal
import nio
from .backend import Backend
from .client import Client
from .model.items import Room, RoomEvent, User
class SignalManager(QObject):
_duplicate_check_lock: Lock = Lock()
_event_handling_lock: Lock = Lock()
def __init__(self, backend: Backend) -> None:
super().__init__(parent=backend)
self.backend = backend
self.last_room_events: Deque[str] = Deque(maxlen=1000)
self._events_in_transfer: int = 0
cm = self.backend.clientManager
cm.clientAdded.connect(self.onClientAdded)
@ -103,28 +106,53 @@ class SignalManager(QObject):
self, _: Client, room_id: str, etype: str, edict: Dict[str, Any]
) -> None:
with self._event_handling_lock:
# Prevent duplicate events in models due to multiple accounts
with self._duplicate_check_lock:
if edict["event_id"] in self.last_room_events:
return
self.last_room_events.appendleft(edict["event_id"])
model = self.backend.models.roomEvents[room_id]
date_time = QDateTime.fromMSecsSinceEpoch(edict["server_timestamp"])
date_time = QDateTime\
.fromMSecsSinceEpoch(edict["server_timestamp"])
new_event = RoomEvent(type=etype, date_time=date_time, dict=edict)
# Model is sorted from newest to oldest message
insert_at = None
if self._events_in_transfer:
local_echoes_met: int = 0
replace_at: Optional[int] = None
# Find if any locally echoed event corresponds to new_event
for i, event in enumerate(model):
if new_event.date_time > event.date_time:
insert_at = i
if not event.is_local_echo:
continue
sb = (event.dict["sender"], event.dict["body"])
new_sb = (new_event.dict["sender"], new_event.dict["body"])
if sb == new_sb:
# The oldest matching local echo shall be replaced
replace_at = max(replace_at or 0, i)
local_echoes_met += 1
if local_echoes_met >= self._events_in_transfer:
break
if insert_at is None:
if replace_at is not None:
model[replace_at] = new_event
self._events_in_transfer -= 1
return
for i, event in enumerate(model):
if event.is_local_echo:
continue
# Model is sorted from newest to oldest message
if new_event.date_time > event.date_time:
model.insert(i, new_event)
return
model.append(new_event)
else:
model.insert(insert_at, new_event)
def onRoomTypingUsersUpdated(
@ -133,3 +161,25 @@ class SignalManager(QObject):
rooms = self.backend.models.rooms[client.userID]
rooms[rooms.indexWhere("room_id", room_id)].typing_users = users
def onMessageAboutToBeSent(
self, client: Client, room_id: str, content: Dict[str, str]
) -> None:
with self._event_handling_lock:
timestamp = QDateTime.currentMSecsSinceEpoch()
model = self.backend.models.roomEvents[room_id]
nio_event = nio.events.RoomMessage.parse_event({
"event_id": "",
"sender": client.userID,
"origin_server_ts": timestamp,
"content": content,
})
event = RoomEvent(
type = type(nio_event).__name__,
date_time = QDateTime.fromMSecsSinceEpoch(timestamp),
dict = nio_event.__dict__,
is_local_echo = True,
)
model.insert(0, event)
self._events_in_transfer += 1

View File

@ -37,13 +37,15 @@ Row {
//Qt.formatDateTime(date_time, "hh:mm:ss") +
//"</font>" +
// (isOwn ? "&nbsp;&nbsp;" + content : "")
//
text: (dict.formatted_body ?
Backend.htmlFilter.filter(dict.formatted_body) :
dict.body) +
"&nbsp;&nbsp;<font size=" + smallSize + "px color=gray>" +
Qt.formatDateTime(date_time, "hh:mm:ss") +
"</font>"
"</font>" +
(is_local_echo ?
"&nbsp;<font size=" + smallSize + "px>⏳</font>" : "")
textFormat: Text.RichText
background: Rectangle {color: "#DDD"}
wrapMode: Text.Wrap