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

@ -21,6 +21,7 @@ class Room(NamedTuple):
class RoomEvent(NamedTuple):
type: str
date_time: QDateTime
dict: Dict[str, str]
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:
# Prevent duplicate events in models due to multiple accounts
with self._duplicate_check_lock:
with self._event_handling_lock:
# Prevent duplicate events in models due to multiple accounts
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"])
new_event = RoomEvent(type=etype, date_time=date_time, dict=edict)
model = self.backend.models.roomEvents[room_id]
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
for i, event in enumerate(model):
if new_event.date_time > event.date_time:
insert_at = i
break
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 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 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
if insert_at is None:
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