diff --git a/include/ircd/m/rooms.h b/include/ircd/m/rooms.h index 34d0eb777..d895e4810 100644 --- a/include/ircd/m/rooms.h +++ b/include/ircd/m/rooms.h @@ -16,28 +16,13 @@ /// namespace ircd::m::rooms { - // All rooms known to IRCd - bool for_each(const string_view &room_id_lb, const room::id::closure_bool &); - bool for_each(const room::id::closure_bool &); - void for_each(const room::id::closure &); - bool for_each(const room::closure_bool &); - void for_each(const room::closure &); + struct each_opts; - // All rooms for a user (alias to interface in user::) - bool for_each(const user &, const string_view &membership, const user::rooms::closure_bool &); - void for_each(const user &, const string_view &membership, const user::rooms::closure &); - bool for_each(const user &, const user::rooms::closure_bool &); - void for_each(const user &, const user::rooms::closure &); - - // All public rooms only; key is either a server hostname or room_id. - // - for server hostname: iterates known rooms from that server. - // - for room_id: starts iteration from that (or closest) room_id - // which can be used as a since/pagination token. - bool for_each_public(const string_view &key, const room::id::closure_bool &); - bool for_each_public(const room::id::closure_bool &); - - size_t count_public(const string_view &server = {}); bool is_public(const room::id &); + size_t count_public(const string_view &server = {}); + + bool for_each(const each_opts &); + template bool for_each(args&&...); // Linkage to utils that build a publicrooms summary from room state. void summary_chunk(const m::room &, json::stack::object &chunk); @@ -46,3 +31,79 @@ namespace ircd::m::rooms event::id::buf summary_set(const m::room &); event::id::buf summary_del(const m::room &); } + +/// Arguments structure to rooms::for_each(). This reduces the API surface to +/// handle a rich set of ways to iterate over the rooms. Several convenience +/// constructors based on common usage are provided; note that these are not +/// the only options patterns. +struct ircd::m::rooms::each_opts +{ + /// If set: select rooms for this user. + m::user user; + + /// If user is set, and this is set: select the membership that user + /// has in the room. + string_view membership; + + /// If set, seek to this room_id or lower-bound to the closest room_id. + string_view key; + + /// All public rooms only; key may be a server hostname or room_id. + /// - for server hostname: iterates known rooms from that server. + /// - for room_id: starts iteration from that (or closest) room_id + /// which can be used as a since/pagination token. + bool public_rooms {false}; + + /// Principal closure for results; invoked synchronously during the call; + /// for-each protocol: return true to continue, false to break. + room::id::closure_bool closure; + + /// Alternative closure when selecting a user. + user::rooms::closure_bool user_closure; + + each_opts(room::id::closure_bool); + each_opts(const string_view &key, room::id::closure_bool); + each_opts(const m::user &user, user::rooms::closure_bool); + each_opts(const m::user &user, const string_view &membership, user::rooms::closure_bool); + each_opts() = default; +}; + +inline +ircd::m::rooms::each_opts::each_opts(room::id::closure_bool closure) +:closure{std::move(closure)} +{} + +inline +ircd::m::rooms::each_opts::each_opts(const string_view &key, + room::id::closure_bool closure) +:key{key} +,closure{std::move(closure)} +{} + +inline +ircd::m::rooms::each_opts::each_opts(const m::user &user, + user::rooms::closure_bool user_closure) +:user{user} +,user_closure{std::move(user_closure)} +{} + +inline +ircd::m::rooms::each_opts::each_opts(const m::user &user, + const string_view &membership, + user::rooms::closure_bool user_closure) +:user{user} +,membership{membership} +,user_closure{std::move(user_closure)} +{} + +template +bool +ircd::m::rooms::for_each(args&&... a) +{ + const each_opts opts + { + std::forward(a)... + }; + + return for_each(opts); +} diff --git a/ircd/m.cc b/ircd/m.cc index 3bfc012b6..a80fc8606 100644 --- a/ircd/m.cc +++ b/ircd/m.cc @@ -3020,38 +3020,17 @@ ircd::m::rooms::summary_chunk(const m::room &room, return function(room, chunk); } -void -ircd::m::rooms::for_each(const user &user, - const user::rooms::closure &closure) -{ - const m::user::rooms rooms{user}; - rooms.for_each(closure); -} - bool -ircd::m::rooms::for_each(const user &user, - const user::rooms::closure_bool &closure) +ircd::m::rooms::for_each(const each_opts &opts) { - const m::user::rooms rooms{user}; - return rooms.for_each(closure); -} + using prototype = bool (const each_opts &); -void -ircd::m::rooms::for_each(const user &user, - const string_view &membership, - const user::rooms::closure &closure) -{ - const m::user::rooms rooms{user}; - rooms.for_each(membership, closure); -} + static mods::import call + { + "m_rooms", "ircd::m::rooms::for_each" + }; -bool -ircd::m::rooms::for_each(const user &user, - const string_view &membership, - const user::rooms::closure_bool &closure) -{ - const m::user::rooms rooms{user}; - return rooms.for_each(membership, closure); + return call(opts); } bool @@ -3080,78 +3059,6 @@ ircd::m::rooms::count_public(const string_view &server) return function(server); } -bool -ircd::m::rooms::for_each_public(const room::id::closure_bool &closure) -{ - return for_each_public(string_view{}, closure); -} - -bool -ircd::m::rooms::for_each_public(const string_view &key, - const room::id::closure_bool &closure) -{ - using prototype = bool (const string_view &, const room::id::closure_bool &); - - static mods::import function - { - "m_rooms", "_for_each_public" - }; - - return function(key, closure); -} - -void -ircd::m::rooms::for_each(const room::closure &closure) -{ - for_each(room::closure_bool{[&closure] - (const room &room) - { - closure(room); - return true; - }}); -} - -bool -ircd::m::rooms::for_each(const room::closure_bool &closure) -{ - return for_each(room::id::closure_bool{[&closure] - (const m::room::id &room_id) - { - return closure(room_id); - }}); -} - -void -ircd::m::rooms::for_each(const room::id::closure &closure) -{ - for_each(string_view{}, [&closure] - (const m::room::id &room_id) - { - closure(room_id); - return true; - }); -} - -bool -ircd::m::rooms::for_each(const room::id::closure_bool &closure) -{ - return for_each(string_view{}, closure); -} - -bool -ircd::m::rooms::for_each(const string_view &room_id_lb, - const room::id::closure_bool &closure) -{ - using prototype = bool (const string_view &, const room::id::closure_bool &); - - static mods::import call - { - "m_rooms", "ircd::m::rooms::for_each" - }; - - return call(room_id_lb, closure); -} - /////////////////////////////////////////////////////////////////////////////// // // m/users.h diff --git a/modules/client/publicrooms.cc b/modules/client/publicrooms.cc index 3ac25f114..22221d87c 100644 --- a/modules/client/publicrooms.cc +++ b/modules/client/publicrooms.cc @@ -122,8 +122,10 @@ get__publicrooms(client &client, my_host() }; - m::rooms::for_each_public(key, [&] - (const m::room::id &room_id) + m::rooms::each_opts opts; + opts.public_rooms = true; + opts.key = key; + opts.closure = [&](const m::room::id &room_id) { json::stack::object obj{chunk}; m::rooms::summary_chunk(room_id, obj); @@ -133,7 +135,9 @@ get__publicrooms(client &client, next_batch_buf = room_id; return ++count < limit; - }); + }; + + m::rooms::for_each(opts); } json::stack::member diff --git a/modules/console.cc b/modules/console.cc index 6ac579536..71e79d1b3 100644 --- a/modules/console.cc +++ b/modules/console.cc @@ -6913,11 +6913,12 @@ console_cmd__eval__file(opt &out, const string_view &line) bool console_cmd__rooms(opt &out, const string_view &line) { - m::rooms::for_each(m::room::id::closure{[&out] + m::rooms::for_each([&out] (const m::room::id &room_id) { out << room_id << std::endl; - }}); + return true; + }); return true; } @@ -6940,13 +6941,17 @@ console_cmd__rooms__public(opt &out, const string_view &line) param.at("limit", 32L) }; - m::rooms::for_each_public(key, [&limit, &out] + m::rooms::each_opts opts; + opts.public_rooms = true; + opts.key = key; + opts.closure = [&limit, &out] (const m::room::id &room_id) -> bool { out << room_id << std::endl; return --limit > 0; - }); + }; + m::rooms::for_each(opts); return true; } @@ -8146,7 +8151,7 @@ console_cmd__room__state__rebuild__present(opt &out, const string_view &line) if(room_id == "*") { - m::rooms::for_each(m::room::id::closure{[&out] + m::rooms::for_each([&out] (const m::room::id &room_id) { const m::room room{room_id}; @@ -8157,7 +8162,8 @@ console_cmd__room__state__rebuild__present(opt &out, const string_view &line) }; out << "done " << room_id << " " << count << std::endl; - }}); + return true; + }); return true; } diff --git a/modules/federation/publicrooms.cc b/modules/federation/publicrooms.cc index fc0b2f0b3..1b7fe0e6b 100644 --- a/modules/federation/publicrooms.cc +++ b/modules/federation/publicrooms.cc @@ -105,14 +105,18 @@ handle_get(client &client, since?: my_host() }; - m::rooms::for_each_public(key, [&] - (const m::room::id &room_id) + m::rooms::each_opts opts; + opts.public_rooms = true; + opts.key = key; + opts.closure = [&](const m::room::id &room_id) { json::stack::object obj{chunk}; m::rooms::summary_chunk(room_id, obj); next_batch_buf = room_id; return ++count < limit; - }); + }; + + m::rooms::for_each(opts); } json::stack::member diff --git a/modules/m_rooms.cc b/modules/m_rooms.cc index 7d3f41467..e005d93f4 100644 --- a/modules/m_rooms.cc +++ b/modules/m_rooms.cc @@ -65,21 +65,35 @@ ircd::m::rooms::create_public_room(const m::event &, bool IRCD_MODULE_EXPORT -ircd::m::rooms::for_each(const string_view &room_id_lb, - const room::id::closure_bool &closure) +ircd::m::rooms::for_each(const each_opts &opts) { + if(opts.user.user_id) + { + const m::user::rooms rooms{opts.user}; + return rooms.for_each(opts.membership, m::user::rooms::closure_bool{[&opts] + (const m::room &room, const string_view &membership) + { + return opts.user_closure? + opts.user_closure(room, membership): + opts.closure(room.room_id); + }}); + } + + if(opts.public_rooms) + return _for_each_public(opts.key, opts.closure); + const room::state state { my_room }; - const room::state::keys_bool keys{[&closure] + const room::state::keys_bool keys{[&opts] (const string_view &room_id) -> bool { - return closure(room_id); + return opts.closure(room_id); }}; - return state.for_each("ircd.room", room_id_lb, keys); + return state.for_each("ircd.room", opts.key, keys); } bool @@ -102,7 +116,7 @@ ircd::m::rooms::_count_public(const string_view &server) return true; }}; - for_each_public(server, count); + _for_each_public(server, count); return ret; }