Fix some edge cases of MAM history fetch
- Wait until we receive our own MUC presence to fetch history - Fix /reconnect weirdness
This commit is contained in:
parent
d3655c4c35
commit
29eef159d5
4 changed files with 83 additions and 18 deletions
|
@ -247,10 +247,10 @@ def schedule_tab_open(tab: tabs.Tab) -> None:
|
||||||
|
|
||||||
async def on_tab_open(tab: tabs.Tab) -> None:
|
async def on_tab_open(tab: tabs.Tab) -> None:
|
||||||
gap = tab._text_buffer.find_last_gap_muc()
|
gap = tab._text_buffer.find_last_gap_muc()
|
||||||
if gap is not None:
|
if gap is None or not gap.leave_message:
|
||||||
await fill_missing_history(tab, gap)
|
|
||||||
else:
|
|
||||||
await on_new_tab_open(tab)
|
await on_new_tab_open(tab)
|
||||||
|
else:
|
||||||
|
await fill_missing_history(tab, gap)
|
||||||
|
|
||||||
|
|
||||||
def schedule_scroll_up(tab: tabs.Tab) -> None:
|
def schedule_scroll_up(tab: tabs.Tab) -> None:
|
||||||
|
|
|
@ -170,7 +170,6 @@ class MucTab(ChatTab):
|
||||||
status=status.message,
|
status=status.message,
|
||||||
show=status.show,
|
show=status.show,
|
||||||
seconds=seconds)
|
seconds=seconds)
|
||||||
mam.schedule_tab_open(self)
|
|
||||||
|
|
||||||
def leave_room(self, message: str):
|
def leave_room(self, message: str):
|
||||||
if self.joined:
|
if self.joined:
|
||||||
|
@ -601,6 +600,7 @@ class MucTab(ChatTab):
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
typ=0)
|
typ=0)
|
||||||
|
mam.schedule_tab_open(self)
|
||||||
|
|
||||||
def handle_presence_joined(self, presence: Presence, status_codes) -> None:
|
def handle_presence_joined(self, presence: Presence, status_codes) -> None:
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -44,8 +44,8 @@ class AckError(Exception):
|
||||||
@dataclass
|
@dataclass
|
||||||
class HistoryGap:
|
class HistoryGap:
|
||||||
"""Class representing a period of non-presence inside a MUC"""
|
"""Class representing a period of non-presence inside a MUC"""
|
||||||
leave_message: Optional[MucOwnLeaveMessage]
|
leave_message: Optional[BaseMessage]
|
||||||
join_message: Optional[MucOwnJoinMessage]
|
join_message: Optional[BaseMessage]
|
||||||
last_timestamp_before_leave: Optional[datetime]
|
last_timestamp_before_leave: Optional[datetime]
|
||||||
first_timestamp_after_join: Optional[datetime]
|
first_timestamp_after_join: Optional[datetime]
|
||||||
|
|
||||||
|
@ -78,33 +78,57 @@ class TextBuffer:
|
||||||
leave, join = None, None
|
leave, join = None, None
|
||||||
for i, item in enumerate(reversed(self.messages)):
|
for i, item in enumerate(reversed(self.messages)):
|
||||||
if isinstance(item, MucOwnLeaveMessage):
|
if isinstance(item, MucOwnLeaveMessage):
|
||||||
leave = (i, item)
|
leave = (len(self.messages) - i - 1, item)
|
||||||
|
break
|
||||||
|
elif join and isinstance(item, MucOwnJoinMessage):
|
||||||
|
leave = (len(self.messages) - i - 1, item)
|
||||||
break
|
break
|
||||||
if isinstance(item, MucOwnJoinMessage):
|
if isinstance(item, MucOwnJoinMessage):
|
||||||
join = (i, item)
|
join = (len(self.messages) - i - 1, item)
|
||||||
if join and leave: # Skip if we find a message in the interval
|
|
||||||
real_leave = len(self.messages) - leave[0] - 1
|
last_timestamp = None
|
||||||
real_join = len(self.messages) - join[0] - 1
|
first_timestamp = datetime.now()
|
||||||
for i in range(real_leave, real_join, 1):
|
|
||||||
|
# Identify the special case when we got disconnected from a chatroom
|
||||||
|
# without receiving or sending the relevant presence, therefore only
|
||||||
|
# having two joins with no leave, and messages in the middle.
|
||||||
|
if leave and isinstance(leave[1], MucOwnJoinMessage):
|
||||||
|
for i in range(join[0] - 1, leave[0], - 1):
|
||||||
|
if isinstance(self.messages[i], Message):
|
||||||
|
leave = (
|
||||||
|
i,
|
||||||
|
self.messages[i]
|
||||||
|
)
|
||||||
|
last_timestamp = self.messages[i].time
|
||||||
|
break
|
||||||
|
# If we have a normal gap but messages inbetween, it probably
|
||||||
|
# already has history, so abort there without returning it.
|
||||||
|
if join and leave:
|
||||||
|
for i in range(leave[0] + 1, join[0], 1):
|
||||||
if isinstance(self.messages[i], Message):
|
if isinstance(self.messages[i], Message):
|
||||||
return None
|
return None
|
||||||
elif not (join or leave):
|
elif not (join or leave):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
# If a leave message is found, get the last Message timestamp
|
||||||
|
# before it.
|
||||||
if leave is None:
|
if leave is None:
|
||||||
last_timestamp, leave_msg = None, None
|
leave_msg = None
|
||||||
else:
|
elif last_timestamp is None:
|
||||||
last_timestamp = None
|
|
||||||
leave_msg = leave[1]
|
leave_msg = leave[1]
|
||||||
for i in range(len(self.messages) - leave[0] - 1, 0, -1):
|
for i in range(leave[0], 0, -1):
|
||||||
if isinstance(self.messages[i], Message):
|
if isinstance(self.messages[i], Message):
|
||||||
last_timestamp = self.messages[i].time
|
last_timestamp = self.messages[i].time
|
||||||
break
|
break
|
||||||
first_timestamp = datetime.now()
|
else:
|
||||||
|
leave_msg = leave[1]
|
||||||
|
# If a join message is found, get the first Message timestamp
|
||||||
|
# after it, or the current time.
|
||||||
if join is None:
|
if join is None:
|
||||||
join_msg = None
|
join_msg = None
|
||||||
else:
|
else:
|
||||||
join_msg = join[1]
|
join_msg = join[1]
|
||||||
for i in range(len(self.messages) - join[0], len(self.messages)):
|
for i in range(join[0], len(self.messages)):
|
||||||
msg = self.messages[i]
|
msg = self.messages[i]
|
||||||
if isinstance(msg, Message) and msg.time < first_timestamp:
|
if isinstance(msg, Message) and msg.time < first_timestamp:
|
||||||
first_timestamp = msg.time
|
first_timestamp = msg.time
|
||||||
|
|
|
@ -35,6 +35,13 @@ def msgs_noleave():
|
||||||
msg4 = Message('4', 'f')
|
msg4 = Message('4', 'f')
|
||||||
return [join, msg3, msg4]
|
return [join, msg3, msg4]
|
||||||
|
|
||||||
|
@fixture(scope='function')
|
||||||
|
def msgs_doublejoin():
|
||||||
|
join = MucOwnJoinMessage('join')
|
||||||
|
msg1 = Message('1', 'd')
|
||||||
|
msg2 = Message('2', 'f')
|
||||||
|
join2 = MucOwnJoinMessage('join')
|
||||||
|
return [join, msg1, msg2, join2]
|
||||||
|
|
||||||
def test_last_message(buf2048):
|
def test_last_message(buf2048):
|
||||||
msg = BaseMessage('toto')
|
msg = BaseMessage('toto')
|
||||||
|
@ -67,6 +74,24 @@ def test_find_gap(buf2048, msgs_noleave):
|
||||||
assert gap.first_timestamp_after_join == msg3.time
|
assert gap.first_timestamp_after_join == msg3.time
|
||||||
|
|
||||||
|
|
||||||
|
def test_find_gap_doublejoin(buf2048, msgs_doublejoin):
|
||||||
|
for msg in msgs_doublejoin:
|
||||||
|
buf2048.add_message(msg)
|
||||||
|
gap = buf2048.find_last_gap_muc()
|
||||||
|
assert gap.leave_message == msgs_doublejoin[2]
|
||||||
|
assert gap.join_message == msgs_doublejoin[3]
|
||||||
|
|
||||||
|
|
||||||
|
def test_find_gap_doublejoin_no_msg(buf2048):
|
||||||
|
join1 = MucOwnJoinMessage('join')
|
||||||
|
join2 = MucOwnJoinMessage('join')
|
||||||
|
for msg in [join1, join2]:
|
||||||
|
buf2048.add_message(msg)
|
||||||
|
gap = buf2048.find_last_gap_muc()
|
||||||
|
assert gap.leave_message is join1
|
||||||
|
assert gap.join_message is join2
|
||||||
|
|
||||||
|
|
||||||
def test_find_gap_already_filled(buf2048):
|
def test_find_gap_already_filled(buf2048):
|
||||||
msg1 = Message('1', 'q')
|
msg1 = Message('1', 'q')
|
||||||
msg2 = Message('2', 's')
|
msg2 = Message('2', 's')
|
||||||
|
@ -115,6 +140,22 @@ def test_get_gap_index(buf2048):
|
||||||
assert buf2048.get_gap_index(gap) == 3
|
assert buf2048.get_gap_index(gap) == 3
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_gap_index_doublejoin(buf2048, msgs_doublejoin):
|
||||||
|
for msg in msgs_doublejoin:
|
||||||
|
buf2048.add_message(msg)
|
||||||
|
gap = buf2048.find_last_gap_muc()
|
||||||
|
assert buf2048.get_gap_index(gap) == 3
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_gap_index_doublejoin_no_msg(buf2048):
|
||||||
|
join1 = MucOwnJoinMessage('join')
|
||||||
|
join2 = MucOwnJoinMessage('join')
|
||||||
|
for msg in [join1, join2]:
|
||||||
|
buf2048.add_message(msg)
|
||||||
|
gap = buf2048.find_last_gap_muc()
|
||||||
|
assert buf2048.get_gap_index(gap) == 1
|
||||||
|
|
||||||
|
|
||||||
def test_get_gap_index_nojoin(buf2048, msgs_nojoin):
|
def test_get_gap_index_nojoin(buf2048, msgs_nojoin):
|
||||||
for msg in msgs_nojoin:
|
for msg in msgs_nojoin:
|
||||||
buf2048.add_message(msg)
|
buf2048.add_message(msg)
|
||||||
|
|
Loading…
Reference in a new issue