construct/modules/client/publicrooms.cc

225 lines
4.1 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.
using namespace ircd;
mapi::header
IRCD_MODULE
{
"Client 7.5 :Public Rooms"
};
m::resource
publicrooms_resource
{
"/_matrix/client/r0/publicRooms",
{
"(7.5) Lists the public rooms on the server. "
}
};
conf::item<size_t>
flush_hiwat
{
{ "name", "ircd.client.publicrooms.flush.hiwat" },
{ "default", 16384L },
};
static m::resource::response
get__publicrooms(client &,
const m::resource::request &);
m::resource::method
post_method
{
publicrooms_resource, "POST", get__publicrooms
};
m::resource::method
get_method
{
publicrooms_resource, "GET", get__publicrooms
};
m::resource::response
get__publicrooms(client &client,
const m::resource::request &request)
{
char since_buf[m::room::id::buf::SIZE];
const string_view &since
{
request.has("since")?
unquote(request["since"]):
url::decode(since_buf, request.query["since"])
};
if(since && !valid(m::id::ROOM, since))
throw m::BAD_REQUEST
{
"Invalid since token for this server."
};
char server_buf[256];
string_view server
{
url::decode(server_buf, request.query["server"])
};
const size_t limit
{
request.has("limit")?
request.at<size_t>("limit"):
request.query.get<size_t>("limit", -1UL)
};
const bool include_all_networks
{
request.get<bool>("include_all_networks", false)
};
const json::object &filter
{
request["filter"]
};
const json::string &search_term
{
filter["generic_search_term"]
};
if(!server && m::valid(m::id::ROOM_ALIAS, search_term))
server = m::id::room_alias(search_term).host();
if(server && !my_host(server)) try
{
m::rooms::summary::fetch
{
server,
since,
limit,
search_term
};
}
catch(const std::exception &e)
{
log::error
{
m::log, "Failed to fetch public rooms from '%s' :%s",
server,
e.what()
};
}
m::resource::response::chunked response
{
client, http::OK
};
json::stack out
{
response.buf, response.flusher(), size_t(flush_hiwat)
};
m::rooms::opts opts;
opts.join_rule = "public";
opts.summary = true;
opts.search_term = search_term;
opts.lower_bound = true;
opts.room_id = since;
opts.request_user_id = request.user_id;
opts.room_type = json::string{filter["room_type"]};
if(m::valid(m::id::USER, search_term))
opts.user_id = search_term;
opts.room_alias =
startswith(search_term, m::id::ROOM_ALIAS)?
string_view{search_term}:
string_view{};
opts.server =
server?
server:
opts.room_alias || opts.user_id?
string_view{}:
my_host();
log::debug
{
m::log, "public rooms query server[%s] search[%s] filter:%s"
" user_id:%b room_alias:%b allnet:%b since:%s",
opts.server,
opts.search_term,
string_view{filter},
bool(opts.user_id),
bool(opts.room_alias),
include_all_networks,
since,
};
size_t count{0};
m::room::id::buf prev_batch_buf; //TODO: XXX
m::room::id::buf next_batch_buf;
json::stack::object top{out};
{
json::stack::array chunk
{
top, "chunk"
};
m::rooms::for_each(opts, [&]
(const m::room::id &room_id)
{
if(++count > limit)
{
next_batch_buf = room_id;
return false;
}
json::stack::object obj
{
chunk
};
m::rooms::summary::get(obj, room_id);
return true;
});
}
// To count the total we clear the since token, otherwise the count
// will be the remainder.
opts.room_id = {};
const size_t total_rooms_count_estimate
{
m::rooms::count(opts)
};
json::stack::member
{
top, "total_room_count_estimate", json::value
{
long(total_rooms_count_estimate)
}
};
if(prev_batch_buf)
json::stack::member
{
top, "prev_batch", prev_batch_buf
};
if(next_batch_buf)
json::stack::member
{
top, "next_batch", next_batch_buf
};
return response;
}