Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F112641
D85.1732340075.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
7 KB
Referenced Files
None
Subscribers
None
D85.1732340075.diff
View Options
diff --git a/src/client/actions/paginate.cpp b/src/client/actions/paginate.cpp
--- a/src/client/actions/paginate.cpp
+++ b/src/client/actions/paginate.cpp
@@ -66,18 +66,34 @@
try {
// kzo.client.dbg() << "We got " << chunk.size() << " events here" << std::endl;
auto room = m.roomList.at(roomId);
- immer::flex_vector_transient<Event> events{};
// The timeline from paginate backwards is returned
// in reversed order, so restore the order.
- zug::into(events, zug::reversed, chunk);
+ auto events = intoImmer(EventList{}, zug::reversed, chunk);
AddToTimelineAction action
- {events.persistent(), paginateBackToken, std::nullopt, gapEventId};
+ {events, paginateBackToken, std::nullopt, gapEventId};
m.roomList = RoomListModel::update(
std::move(m.roomList),
UpdateRoomAction{roomId, action});
+ m.roomList = RoomListModel::update(
+ std::move(m.roomList),
+ UpdateRoomAction{roomId, MaybeAddStateEventsAction{
+ intoImmer(EventList{},
+ zug::filter(&Event::isState),
+ events)
+ }});
+
+ // r.state() contains state events prior to the timeline
+ // we add them later than the timeline, so the states in the
+ // timeline takes priority
+ m.roomList = RoomListModel::update(
+ std::move(m.roomList),
+ UpdateRoomAction{roomId, MaybeAddStateEventsAction{
+ r.state()
+ }});
+
m.addTrigger(PaginateSuccessful{roomId});
return { std::move(m), lager::noop };
diff --git a/src/client/room/room-model.hpp b/src/client/room/room-model.hpp
--- a/src/client/room/room-model.hpp
+++ b/src/client/room/room-model.hpp
@@ -65,6 +65,14 @@
immer::flex_vector<Event> stateEvents;
};
+ /// Go from the back of stateEvents to the beginning,
+ /// adding the event to room state only if the room
+ /// has no state event with that state key.
+ struct MaybeAddStateEventsAction
+ {
+ immer::flex_vector<Event> stateEvents;
+ };
+
struct AddToTimelineAction
{
/// Events from oldest to latest
@@ -284,6 +292,7 @@
using Action = std::variant<
AddStateEventsAction,
+ MaybeAddStateEventsAction,
AddToTimelineAction,
AddAccountDataAction,
ChangeMembershipAction,
diff --git a/src/client/room/room-model.cpp b/src/client/room/room-model.cpp
--- a/src/client/room/room-model.cpp
+++ b/src/client/room/room-model.cpp
@@ -1,6 +1,6 @@
/*
* This file is part of libkazv.
- * SPDX-FileCopyrightText: 2020-2023 tusooa
+ * SPDX-FileCopyrightText: 2020-2024 tusooa <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
@@ -72,6 +72,18 @@
}
return r;
},
+ [&](MaybeAddStateEventsAction a) {
+ for (auto it = a.stateEvents.rbegin();
+ it != a.stateEvents.rend();
+ ++it) {
+ const auto &e = *it;
+ auto k = keyOfState(e);
+ if (!r.stateEvents.count(k)) {
+ r.stateEvents = std::move(r.stateEvents).set(k, e);
+ }
+ }
+ return r;
+ },
[&](AddToTimelineAction a) {
auto eventIds = intoImmer(immer::flex_vector<std::string>(),
zug::map(keyOfTimeline), a.events);
diff --git a/src/tests/client/paginate-test.cpp b/src/tests/client/paginate-test.cpp
--- a/src/tests/client/paginate-test.cpp
+++ b/src/tests/client/paginate-test.cpp
@@ -14,7 +14,7 @@
#include <cursorutil.hpp>
#include <sdk-model.hpp>
#include <client/client.hpp>
-
+#include <client/actions/paginate.hpp>
#include "client-test-util.hpp"
#include "factory.hpp"
#include <iostream>
@@ -88,6 +88,36 @@
"age": 1234
}
}
+ ],
+ "state": [
+ {
+ "content": {
+ "name": "The original room name"
+ },
+ "type": "m.room.name",
+ "event_id": "$some:example.org",
+ "room_id": "!foo:example.org",
+ "sender": "@example:example.org",
+ "origin_server_ts": 1432735824653,
+ "unsigned": {
+ "age": 1234
+ },
+ "state_key": ""
+ },
+ {
+ "content": {
+ "membership": "join"
+ },
+ "type": "m.room.member",
+ "event_id": "$some-1:example.org",
+ "room_id": "!foo:example.org",
+ "sender": "@example:example.org",
+ "origin_server_ts": 1432735824653,
+ "unsigned": {
+ "age": 1234
+ },
+ "state_key": "@example:example.org"
+ }
]
})"_json;
@@ -258,3 +288,27 @@
REQUIRE(! timelineGaps.find("$event1:example.org"));
}
+
+TEST_CASE("paginating should add the state events to room state", "[client][paginate]")
+{
+ ClientModel m = makeClient(
+ withRoom(makeRoom(
+ withRoomId("!foo:example.org")
+ | withRoomTimeline({event1, event2})
+ | withRoomTimelineGaps({{event1.id(), "prevBatchForEvent1"}})
+ ))
+ );
+
+ auto resp = makeResponse(
+ "GetRoomEvents",
+ withResponseJsonBody(paginateResponseJson)
+ | withResponseDataKV("roomId", "!foo:example.org")
+ | withResponseDataKV("gapEventId", "$event1:example.org")
+ );
+
+ auto [next, _] = processResponse(m, GetRoomEventsResponse(resp));
+ auto r = next.roomList.rooms["!foo:example.org"];
+
+ REQUIRE(r.stateEvents[KeyOfState{"m.room.name", ""}].content().get().at("name") == "The room name");
+ REQUIRE(r.stateEvents[KeyOfState{"m.room.member", "@example:example.org"}].content().get().at("membership") == "join");
+}
diff --git a/src/tests/client/room/room-actions-test.cpp b/src/tests/client/room/room-actions-test.cpp
--- a/src/tests/client/room/room-actions-test.cpp
+++ b/src/tests/client/room/room-actions-test.cpp
@@ -1,6 +1,6 @@
/*
* This file is part of libkazv.
- * SPDX-FileCopyrightText: 2021 Tusooa Zhu <tusooa@kazv.moe>
+ * SPDX-FileCopyrightText: 2021-2024 tusooa <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
@@ -9,8 +9,10 @@
#include <catch2/catch_all.hpp>
#include <room/room-model.hpp>
+#include <testfixtures/factory.hpp>
using namespace Kazv;
+using namespace Kazv::Factory;
TEST_CASE("SetHeroIdsAction", "[client][room]")
{
@@ -118,3 +120,24 @@
REQUIRE(res.messages[eventId].content().get() == json::object());
REQUIRE(res.messages[eventId].redacted());
}
+
+TEST_CASE("MaybeAddStateEventsAction", "[client][room]")
+{
+ auto r = makeRoom(withRoomState({
+ makeEvent(withEventType("m.room.member") | withStateKey("@foo:example.com") | withEventContent(json{{"membership", "join"}})),
+ }));
+
+ auto next = RoomModel::update(r, MaybeAddStateEventsAction{{
+ // already exists, should not add
+ makeEvent(withEventType("m.room.member") | withStateKey("@foo:example.com") | withEventContent(json{{"membership", "leave"}})),
+ // does not exist yet but the one below should be used
+ makeEvent(withEventType("m.room.member") | withStateKey("@bar:example.com") | withEventContent(json{{"membership", "leave"}})),
+ // does not exist, should add
+ makeEvent(withEventType("m.room.member") | withStateKey("@bar:example.com") | withEventContent(json{{"membership", "join"}})),
+ }});
+
+ REQUIRE(next.stateEvents.count(KeyOfState{"m.room.member", "@foo:example.com"}));
+ REQUIRE(next.stateEvents[KeyOfState{"m.room.member", "@foo:example.com"}].content().get()["membership"] == "join");
+ REQUIRE(next.stateEvents.count(KeyOfState{"m.room.member", "@bar:example.com"}));
+ REQUIRE(next.stateEvents[KeyOfState{"m.room.member", "@bar:example.com"}].content().get()["membership"] == "join");
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Nov 22, 9:34 PM (21 m, 16 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
39116
Default Alt Text
D85.1732340075.diff (7 KB)
Attached To
Mode
D85: Amend room state when paginating back
Attached
Detach File
Event Timeline
Log In to Comment