// Matrix Construct // // Copyright (C) Matrix Construct Developers, Authors & Contributors // Copyright (C) 2016-2018 Jason Volk // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice is present in all copies. The // full license for this software is available in the LICENSE file. decltype(ircd::m::rooms::opts_default) ircd::m::rooms::opts_default; void ircd::m::rooms::dump__file(const opts &opts, const string_view &filename) { const fs::fd file { filename, fs::fd::opts { .mode = std::ios::out | std::ios::app, }, }; // POSIX_FADV_DONTNEED fs::evict(file); size_t len(0), num(0); for_each(opts, [&](const auto &room_id) { const const_buffer bufs[] { room_id, "\n"_sv }; len += fs::append(file, bufs); ++num; char pbuf[48]; log::info { log, "dump[%s] rooms:%zu %s %s", filename, num, pretty(pbuf, iec(len)), string_view{room_id}, }; return true; }); char pbuf[48]; log::notice { log, "dump[%s] complete rooms:%zu using %s", filename, num, pretty(pbuf, iec(len)), }; } bool ircd::m::rooms::has(const opts &opts) { return !for_each(opts, [] (const m::room::id &) noexcept { // false to break; for_each() returns false return false; }); } size_t ircd::m::rooms::count(const opts &opts) { size_t ret{0}; for_each(opts, [&ret] (const m::room::id &) noexcept { ++ret; return true; }); return ret; } bool ircd::m::rooms::for_each(const room::id::closure_bool &closure) { return for_each(opts_default, closure); } bool ircd::m::rooms::for_each(const opts &opts, const room::id::closure_bool &closure) { bool ret{true}; const auto proffer{[&opts, &closure, &ret] (const m::room::id &room_id) { if(opts.room_id && !opts.lower_bound) { ret = false; return; } const m::room room { room_id }; if(opts.room_id) if(room_id < opts.room_id) return; if(opts.local_joined_only) if(!local_joined(room)) return; if(opts.remote_joined_only) if(!remote_joined(room)) return; if(opts.local_only) if(!local_only(room)) return; if(opts.remote_only) if(local_only(room)) return; if(opts.server && !opts.summary) if(opts.server != room_id.host()) return; if(opts.join_rule && !opts.summary) if(!join_rule(room, opts.join_rule)) return; if(opts.room_type) if(!m::type(room_id, opts.room_type)) return; if(opts.server && opts.request_node_id && my_host(opts.server)) if(!room::aliases(room_id).has_server(opts.server)) return; if(opts.room_alias) { const auto match_alias_prefix{[&opts](const auto &alias) { return !startswith(alias, opts.room_alias); }}; if(room::aliases(room).for_each(match_alias_prefix)) return; // no match } ret = closure(room); }}; // branch for public rooms of a specific user if(opts.user_id) { const user::rooms user_rooms { opts.user_id }; return user_rooms.for_each(user::rooms::closure_bool{[&proffer, &ret] (const room::id &room_id, const string_view &membership) { proffer(room_id); return ret; }}); } // branch for optimized public rooms searches. if(opts.summary) { const room::id::buf public_room_id { "!public", my_host() }; const room::state state { public_room_id }; state.for_each("ircd.rooms.summary", [&opts, &proffer, &ret] (const string_view &type, const string_view &state_key, const event::idx &event_idx) { const auto &[room_id, origin] { rooms::summary::unmake_state_key(state_key) }; if(opts.server && origin != opts.server) return true; proffer(room_id); return ret; }); return ret; } ctx::dock dock; size_t fetch {0}, fetched {0}; const auto fetcher{[&] (const string_view &type, const event::idx &event_idx) { ++fetch; fetched += m::get(std::nothrow, event_idx, "room_id", proffer); dock.notify_one(); return ret; }}; size_t prefetch {0}, prefetched {0}; const auto prefetcher{[&] (const string_view &type, const event::idx &event_idx) { ++prefetch; prefetched += m::prefetch(event_idx, "room_id"); dock.wait([&]() noexcept { return fetch + opts.prefetch > prefetch; }); return ret; }}; if(!opts.prefetch) return events::type::for_each_in("m.room.create", fetcher); const ctx::context prefetch_worker { "m.rooms.prefetch", [&prefetcher] { events::type::for_each_in("m.room.create", prefetcher); } }; return events::type::for_each_in("m.room.create", fetcher); } // // ircd::m::rooms::opts::opts // ircd::m::rooms::opts::opts(const string_view &input) noexcept :room_id { valid(m::id::ROOM, input)? m::id::room{input}: m::id::room{} } ,server { startswith(input, ':')? lstrip(input, ':'): string_view{} } ,room_alias { valid(m::id::ROOM_ALIAS, input)? m::id::room_alias{input}: m::id::room_alias{} } ,user_id { valid(m::id::USER, input)? m::id::user{input}: m::id::user{} } ,local_only { has(input, "local_only") } ,remote_only { has(input, "remote_only") } ,local_joined_only { has(input, "local_joined_only") } ,remote_joined_only { has(input, "remote_joined_only") } ,search_term { !room_id && !server && !room_alias && !user_id && !local_only && !remote_only && !local_joined_only && !remote_joined_only? input: string_view{} } { }