From eb3b4d82fbec757fb58ee72297680b1cb9cf6dec Mon Sep 17 00:00:00 2001 From: Jason Volk Date: Tue, 23 Jul 2019 19:31:40 -0700 Subject: [PATCH] ircd::m::room::members: Simplify and improve interface; callsites. --- include/ircd/m/room/members.h | 19 +-- ircd/m.cc | 15 +- ircd/m_room.cc | 290 +++++++++++--------------------- modules/client/initialsync.cc | 6 +- modules/client/rooms/members.cc | 32 ++-- modules/console.cc | 77 +++++++-- modules/m_direct.cc | 4 +- 7 files changed, 195 insertions(+), 248 deletions(-) diff --git a/include/ircd/m/room/members.h b/include/ircd/m/room/members.h index 5049b03c4..c4ec91374 100644 --- a/include/ircd/m/room/members.h +++ b/include/ircd/m/room/members.h @@ -23,19 +23,18 @@ namespace ircd::m /// struct ircd::m::room::members { - using closure = std::function; - using closure_bool = std::function; + using closure_idx = std::function; + using closure = std::function; + + static string_view membership(const mutable_buffer &out, const event::idx &); + static bool membership(const event::idx &, const string_view &); m::room room; - bool for_each(const string_view &membership, const event::closure_bool &) const; - void for_each(const string_view &membership, const event::closure &) const; - bool for_each(const string_view &membership, const closure_bool &) const; - void for_each(const string_view &membership, const closure &) const; - bool for_each(const event::closure_bool &) const; - void for_each(const event::closure &) const; - bool for_each(const closure_bool &) const; - void for_each(const closure &) const; + bool for_each(const string_view &membership, const closure &) const; + bool for_each(const string_view &membership, const closure_idx &) const; + bool for_each(const closure &) const; + bool for_each(const closure_idx &) const; bool empty(const string_view &membership) const; bool empty() const; diff --git a/ircd/m.cc b/ircd/m.cc index 49c3fb5da..f017355a0 100644 --- a/ircd/m.cc +++ b/ircd/m.cc @@ -3082,15 +3082,14 @@ const }; room.fopts = &fopts; - const m::room::members members{room}; - return members.for_each(membership, event::closure_bool{[&seen, &closure] - (const m::event &event) + const m::room::members members { - const auto &other - { - at<"state_key"_>(event) - }; + room + }; + return members.for_each(membership, [&seen, &closure] + (const user::id &other) + { const auto it { seen.lower_bound(other) @@ -3101,7 +3100,7 @@ const seen.emplace_hint(it, std::string{other}); return closure(m::user{other}); - }}); + }); }}); } diff --git a/ircd/m_room.cc b/ircd/m_room.cc index db97a21c1..865ed08da 100644 --- a/ircd/m_room.cc +++ b/ircd/m_room.cc @@ -1237,15 +1237,15 @@ const { user::id::buf ret; const members members{*this}; - members.for_each(membership, members::closure_bool{[&host, &ret] - (const id::user &user_id) + members.for_each(membership, [&host, &ret] + (const auto &user_id, const auto &event_idx) { if(host && user_id.host() != host) return true; ret = user_id; return false; - }}); + }); return ret; } @@ -3068,57 +3068,16 @@ bool ircd::m::room::members::empty() const { - const room::state state - { - room - }; - - // for_each() returns true when it reaches the end of the iteration. - return state.for_each("m.room.member", state::closure_bool{[] - (const auto &type, const auto &state_key, const auto &event_idx) - { - return false; - }}); + return empty(string_view{}); } bool ircd::m::room::members::empty(const string_view &membership) const { - const room::state state + return for_each(membership, closure{[](const auto &) { - room - }; - - // joined members optimization. Only possible when seeking - // membership="join" on the present state of the room. - if(membership == "join" && state.present()) - { - // _for_each() returns true when it reaches the end of the iteration. - const room::origins origins{room}; - return origins._for_each(origins, [] - (const string_view &) - { - // closure returns false to break causing _for_each() to return false. - return false; - }); - } - - // for_each() returns true when it reaches the end of the iteration. - return state.for_each("m.room.member", state::closure_bool{[&membership] - (const auto &type, const auto &state_key, const auto &event_idx) - { - // return false if the query succeeds, breaking the iteration. - return !m::query(std::nothrow, event_idx, "content", [&membership] - (const json::object &content) - { - const json::string &content_membership - { - content["membership"] - }; - - return !membership || content_membership == membership; - }); + return false; }}); } @@ -3126,178 +3085,98 @@ size_t ircd::m::room::members::count() const { - const room::state state - { - room - }; - - return state.count("m.room.member"); + return count(string_view{}); } size_t ircd::m::room::members::count(const string_view &membership) const { - // Allow empty membership string to count all memberships - if(!membership) - return count(); - - // joined members optimization. Only possible when seeking - // membership="join" on the present state of the room. - if(membership == "join" && state{room}.present()) - { - size_t ret{0}; - const room::origins origins{room}; - origins._for_each(origins, [&ret](const string_view &) - { - ++ret; - return true; - }); - - return ret; - } - - static const event::keys::include keys - { - "content", - }; - - const m::event::fetch::opts fopts - { - keys, room.fopts? room.fopts->gopts : db::gopts{} - }; - - const room::state state - { - room, &fopts - }; - size_t ret{0}; - state.for_each("m.room.member", event::closure{[&ret, &membership] - (const m::event &event) + this->for_each(membership, room::members::closure{[&ret] + (const id::user &) { - ret += m::membership(event) == membership; + ++ret; + return true; }}); return ret; } -void -ircd::m::room::members::for_each(const closure &closure) -const -{ - for_each(string_view{}, closure); -} - bool -ircd::m::room::members::for_each(const closure_bool &closure) +ircd::m::room::members::for_each(const closure &closure) const { return for_each(string_view{}, closure); } -void -ircd::m::room::members::for_each(const event::closure &closure) +bool +ircd::m::room::members::for_each(const closure_idx &closure) const { - for_each(string_view{}, closure); + return for_each(string_view{}, closure); } bool -ircd::m::room::members::for_each(const event::closure_bool &closure) +ircd::m::room::members::for_each(const string_view &membership, + const closure_idx &closure) const { - const room::state state{room}; - return state.for_each("m.room.member", event::closure_bool{[&closure] - (const m::event &event) + const m::room::state state { - return closure(event); - }}); + room + }; + + const bool present + { + state.present() + }; + + // joined members optimization. Only possible when seeking + // membership="join" on the present state of the room. + if(membership == "join" && present) + return this->for_each(membership, [&closure, &state, this] + (const id::user &member) + { + const auto event_idx + { + state.get(std::nothrow, "m.room.member", member) + }; + + assert(event_idx); + return event_idx? + closure(member, event_idx): + true; + }); + + return state.for_each("m.room.member", [this, &membership, &closure] + (const string_view &type, const string_view &state_key, const event::idx &event_idx) + { + return !membership || this->membership(event_idx, membership)? + closure(state_key, event_idx): + true; + }); } -void +bool ircd::m::room::members::for_each(const string_view &membership, const closure &closure) const { - for_each(membership, closure_bool{[&closure] - (const user::id &user_id) + const m::room::state state { - closure(user_id); - return true; - }}); -} - -/// Iterate the mxid's of the users in the room, optionally with a specific -/// membership state. This query contains internal optimizations as the closure -/// only requires a user::id. The db::gopts set in the room.fopts pointer is -/// still used if provided. -bool -ircd::m::room::members::for_each(const string_view &membership, - const closure_bool &closure) -const -{ - // Setup the list of event fields to fetch for the closure - static const event::keys::include keys - { - "state_key", "content", + room }; - // In this case the fetch opts isn't static so it can maintain the - // previously given db::gopts, but it will use our keys list. - const m::event::fetch::opts fopts + const bool present { - keys, room.fopts? room.fopts->gopts : db::gopts{} + state.present() }; - // Stack-over the the current fetch opts with our new opts for this query, - // putting them back when we're finished. This requires a const_cast which - // should be okay here. - auto &room(const_cast(this->room)); - const scope_restore theirs - { - room.fopts, &fopts - }; - - return for_each(membership, event::closure_bool{[&closure] - (const event &event) - { - const user::id &user_id - { - at<"state_key"_>(event) - }; - - return closure(user_id); - }}); -} - -void -ircd::m::room::members::for_each(const string_view &membership, - const event::closure &closure) -const -{ - for_each(membership, event::closure_bool{[&closure] - (const m::event &event) - { - closure(event); - return true; - }}); -} - -bool -ircd::m::room::members::for_each(const string_view &membership, - const event::closure_bool &closure) -const -{ - if(empty(membership)) - return for_each(closure); - // joined members optimization. Only possible when seeking // membership="join" on the present state of the room. - if(!room.event_id && membership == "join") - { - const room::origins origins{room}; - return origins._for_each(origins, [&closure, this] + if(membership == "join" && present) + return room::origins::_for_each(room, [this, &closure] (const string_view &key) { const string_view &member @@ -3305,26 +3184,49 @@ const std::get<1>(dbs::room_joined_key(key)) }; - bool ret{true}; - room.get(std::nothrow, "m.room.member", member, event::closure{[&closure, &ret] - (const event &event) - { - ret = closure(event); - }}); - - return ret; + return closure(member); }); - } - return for_each(event::closure_bool{[&membership, &closure] - (const event &event) + return this->for_each(membership, [&closure] + (const auto &user_id, const auto &event_idx) { - if(m::membership(event) == membership) - if(!closure(event)) - return false; + return closure(user_id); + }); +} - return true; - }}); +bool +ircd::m::room::members::membership(const event::idx &event_idx, + const string_view &membership) +{ + return m::query(std::nothrow, event_idx, "content", [&membership] + (const json::object &content) + { + const json::string &content_membership + { + content["membership"] + }; + + return content_membership && content_membership == membership; + }); +} + +ircd::string_view +ircd::m::room::members::membership(const mutable_buffer &out, + const event::idx &event_idx) +{ + return m::query(std::nothrow, event_idx, "content", [&out] + (const json::object &content) -> string_view + { + const json::string &content_membership + { + content["membership"] + }; + + return strlcpy + { + out, content_membership + }; + }); } // diff --git a/modules/client/initialsync.cc b/modules/client/initialsync.cc index 309e7d02e..3fd52e433 100644 --- a/modules/client/initialsync.cc +++ b/modules/client/initialsync.cc @@ -596,7 +596,7 @@ initialsync_room_ephemeral_events(client &client, //TODO: We're skipping receipts from members who left so we enjoy the //TODO: joined members optimizations. Need to figure out if anyone //TODO: left in the synced timeline and include them manually. - members.for_each("join", m::room::members::closure{[&events, &room] + members.for_each("join", [&events, &room] (const m::user &user) { const m::user::room user_room{user}; @@ -644,7 +644,9 @@ initialsync_room_ephemeral_events(client &client, }; } }); - }}); + + return true; + }); } void diff --git a/modules/client/rooms/members.cc b/modules/client/rooms/members.cc index c424e1cfa..6b3254bea 100644 --- a/modules/client/rooms/members.cc +++ b/modules/client/rooms/members.cc @@ -99,15 +99,23 @@ get__members(client &client, room }; - members.for_each(membership, m::event::closure_bool{[&request, &chunk, ¬_membership] - (const m::event &event) + members.for_each(membership, [&request, &chunk, ¬_membership] + (const m::user::id &member, const m::event::idx &event_idx) { - if(m::membership(event) == not_membership) + if(m::room::members::membership(event_idx, not_membership)) + return true; + + const m::event::fetch event + { + event_idx, std::nothrow + }; + + if(!event.valid) return true; chunk.append(event); return true; - }}); + }); return std::move(response); } @@ -161,17 +169,9 @@ get__joined_members(client &client, room }; - members.for_each("join", m::room::members::closure{[&joined, &room] - (const m::user::id &user_id) + members.for_each("join", [&joined, &room] + (const m::user::id &user_id, const m::event::idx &event_idx) { - const m::event::idx &event_idx - { - room.get(std::nothrow, "m.room.member", user_id) - }; - - if(!event_idx) - return; - json::stack::object room_member { joined, user_id @@ -186,7 +186,9 @@ get__joined_members(client &client, room_member, key, val }; }); - }}); + + return true; + }); return std::move(response); } diff --git a/modules/console.cc b/modules/console.cc index 845a59c3e..94d255d49 100644 --- a/modules/console.cc +++ b/modules/console.cc @@ -8217,9 +8217,9 @@ console_cmd__room__members(opt &out, const string_view &line) m::room_id(param.at(0)) }; - const string_view membership + const string_view &membership { - param.at(1, "join"_sv) + param[1] }; const m::room room @@ -8232,14 +8232,30 @@ console_cmd__room__members(opt &out, const string_view &line) room }; - const m::room::members::closure closure{[&out, &membership] - (const m::user::id &user_id) + if(membership) { - out << std::setw(8) << std::left << membership - << " " << user_id << std::endl; - }}; + members.for_each(membership, [&out, &membership] + (const m::user::id &user_id) + { + out << std::setw(8) << std::left << membership + << " " << user_id << std::endl; + + return true; + }); + + return true; + } + + members.for_each(membership, [&out] + (const m::user::id &user_id, const m::event::idx &event_idx) + { + char buf[32]; + out << std::setw(8) << std::left << m::room::members::membership(buf, event_idx) + << " " << user_id << std::endl; + + return true; + }); - members.for_each(membership, closure); return true; } @@ -8271,9 +8287,18 @@ console_cmd__room__members__events(opt &out, const string_view &line) room }; - const auto closure{[&out](const m::event &event) + const auto closure{[&out](const auto &user_id, const auto &event_idx) { + const m::event::fetch event + { + event_idx, std::nothrow + }; + + if(!event.valid) + return true; + out << pretty_oneline(event) << std::endl; + return true; }}; members.for_each(membership, closure); @@ -8346,12 +8371,30 @@ console_cmd__room__members__origin(opt &out, const string_view &line) }; members.for_each(membership, [&out, &origin] - (const m::event &event) + (const auto &user_id, const auto &event_idx) { - if(json::get<"origin"_>(event) != origin) - return; + const bool same_origin + { + m::query(std::nothrow, event_idx, "origin", [&origin] + (const auto &_origin) + { + return _origin == origin; + }) + }; + + if(!same_origin) + return true; + + const m::event::fetch event + { + event_idx, std::nothrow + }; + + if(!event.valid) + return true; out << pretty_oneline(event) << std::endl; + return true; }); return true; @@ -8404,12 +8447,12 @@ console_cmd__room__members__read(opt &out, const string_view &line) << std::endl; }}; - const auto member_closure{[&room_id, event_closure] - (const m::event &event) + members.for_each(membership, [&room_id, &event_closure] + (const m::user::id &user_id, const m::event::idx &event_idx) { const m::user user { - at<"state_key"_>(event) + user_id }; static const m::event::fetch::opts fopts @@ -8429,9 +8472,9 @@ console_cmd__room__members__read(opt &out, const string_view &line) }; user_room.get(std::nothrow, "ircd.read", room_id, event_closure); - }}; + return true; + }); - members.for_each(membership, member_closure); return true; } diff --git a/modules/m_direct.cc b/modules/m_direct.cc index 2c0b8bf78..75da8a519 100644 --- a/modules/m_direct.cc +++ b/modules/m_direct.cc @@ -75,7 +75,7 @@ _join_room__m_direct(const m::event &event, m::user::id::buf other_person; const m::room::members members{room}; - members.for_each(m::room::members::closure_bool{[&user_id, &other_person] + members.for_each([&user_id, &other_person] (const auto &other_id) { if(other_id == user_id) @@ -83,7 +83,7 @@ _join_room__m_direct(const m::event &event, other_person = other_id; return false; - }}); + }); if(!other_person) return;