Add local echoing of messages
As per https://matrix.org/docs/spec/client_server/latest.html#local-echo
This commit is contained in:
parent
e9b3628fcc
commit
11d900965a
3
TODO.md
3
TODO.md
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -37,13 +37,15 @@ Row {
|
|||
//Qt.formatDateTime(date_time, "hh:mm:ss") +
|
||||
//"</font>" +
|
||||
// (isOwn ? " " + content : "")
|
||||
|
||||
//
|
||||
text: (dict.formatted_body ?
|
||||
Backend.htmlFilter.filter(dict.formatted_body) :
|
||||
dict.body) +
|
||||
" <font size=" + smallSize + "px color=gray>" +
|
||||
Qt.formatDateTime(date_time, "hh:mm:ss") +
|
||||
"</font>"
|
||||
"</font>" +
|
||||
(is_local_echo ?
|
||||
" <font size=" + smallSize + "px>⏳</font>" : "")
|
||||
textFormat: Text.RichText
|
||||
background: Rectangle {color: "#DDD"}
|
||||
wrapMode: Text.Wrap
|
||||
|
|
Loading…
Reference in New Issue
Block a user