construct/matrix/rooms.cc

305 lines
5.4 KiB
C++

// Matrix Construct
//
// Copyright (C) Matrix Construct Developers, Authors & Contributors
// Copyright (C) 2016-2018 Jason Volk <jason@zemos.net>
//
// 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{}
}
{
}