From f7a4f5c9397c6714d62109388db159143861bd0b Mon Sep 17 00:00:00 2001 From: Jason Volk Date: Wed, 28 Feb 2018 21:25:25 -0800 Subject: [PATCH] modules/client/rooms/initialsync: Checkpoint what's here for now. --- modules/client/rooms/initialsync.cc | 232 ++++++++++++++++++++++++++-- 1 file changed, 223 insertions(+), 9 deletions(-) diff --git a/modules/client/rooms/initialsync.cc b/modules/client/rooms/initialsync.cc index e8548b518..99c82a720 100644 --- a/modules/client/rooms/initialsync.cc +++ b/modules/client/rooms/initialsync.cc @@ -10,27 +10,241 @@ using namespace ircd; +static resource::response +get__initialsync_remote(client &client, + const resource::request &request, + const m::room::id &room_id) +{ + // only used for headers + const unique_buffer state_buffer + { + 8_KiB + }; + + // only used for headers + const unique_buffer backfill_buffer + { + 8_KiB + }; + + m::v1::state state_request + { + room_id, state_buffer, + }; + + m::v1::backfill::opts bf_opts; + bf_opts.limit = 1024; + m::v1::backfill backfill_request + { + room_id, backfill_buffer, std::move(bf_opts) + }; + + const auto when + { + ircd::now() + seconds(15) //TODO: conf + }; + + std::vector messages; + messages.reserve(bf_opts.limit); + if(backfill_request.wait_until(when) != ctx::future_status::timeout) + { + const auto &code{backfill_request.get()}; + const json::object &response{backfill_request}; + const json::array &pdus + { + response.get("pdus") + }; + + for(const json::object &event : pdus) + messages.emplace_back(event); + + std::sort(std::begin(messages), std::end(messages), [] + (const auto &a, const auto &b) + { + return at<"depth"_>(a) < at<"depth"_>(b); + }); + } + else cancel(backfill_request); + + std::vector state; + if(state_request.wait_until(when) != ctx::future_status::timeout) + { + const auto &code{state_request.get()}; + const json::object &response{state_request}; + const json::array &auth_chain + { + response.get("auth_chain") + }; + + const json::array &pdus + { + response.get("pdus") + }; + + state.reserve(auth_chain.size() + pdus.size()); + for(const json::object &event : auth_chain) + state.emplace_back(event); + + for(const json::object &event : pdus) + state.emplace_back(event); + + std::sort(std::begin(state), std::end(state), [] + (const auto &a, const auto &b) + { + return at<"depth"_>(a) < at<"depth"_>(b); + }); + } + else cancel(state_request); + + const string_view membership{"join"}; + const string_view visibility{"public"}; + std::vector account_data; + + const json::strung chunk + { + messages.data(), messages.data() + messages.size() + }; + + const json::strung states + { + state.data(), state.data() + state.size() + }; + + resource::response + { + client, json::members + { + { "room_id", room_id }, + { "membership", membership }, + { "state", states }, + { "visibility", visibility }, + { "account_data", { account_data.data(), account_data.size() } }, + { "messages", json::members + { + { "chunk", chunk } + }}, + } + }; + + m::vm::opts vmopts; + m::vm::eval eval{vmopts}; + + vmopts.non_conform.set(m::event::conforms::MISSING_PREV_STATE); + vmopts.non_conform.set(m::event::conforms::MISSING_MEMBERSHIP); + vmopts.prev_check_exists = false; + vmopts.nothrows = -1U; + + for(const auto &event : state) + eval(event); + + for(const auto &event : messages) + eval(event); + + return {}; // already returned +} + resource::response get__initialsync(client &client, const resource::request &request, const m::room::id &room_id) { - const string_view membership{}; + if(!exists(room_id)) + { + if(!my(room_id)) + return get__initialsync_remote(client, request, room_id); + + throw m::NOT_FOUND + { + "room_id '%s' does not exist", room_id + }; + } + + const m::room room + { + room_id + }; + + std::vector state; + { + const m::room::state state_ + { + room_id + }; + + state.reserve(state_.count()); + state_.for_each([&state](const m::event &event) + { + state.emplace_back(json::strung(event)); + }); + } + + std::vector messages; + { + messages.reserve(20); + m::room::messages it{room}; + for(; it && messages.size() < 20; --it) + messages.emplace_back(json::strung(*it)); + + std::reverse(begin(messages), end(messages)); + } + + char membership_buffer[64]; + const string_view membership + { + room.membership(membership_buffer, m::user::id{request.user_id}) + }; + + //TODO: XXX const string_view visibility{"public"}; - std::vector messages; - std::vector state; + + //TODO: XXX std::vector account_data; + const json::value account_datas + { + account_data.data(), account_data.size() + }; + + //TODO: derp + const json::strung states + { + state.data(), state.data() + state.size() + }; + + //TODO: derp + const json::strung messages_chunk + { + messages.data(), messages.data() + messages.size() + }; + + const string_view &messages_start + { + !messages.empty()? + unquote(json::object{messages.front()}.at("event_id")): + string_view{} + }; + + const string_view &messages_end + { + !messages.empty()? + unquote(json::object{messages.back()}.at("event_id")): + string_view{} + }; return resource::response { client, json::members { - { "room_id", room_id }, - { "membership", membership }, - { "messages", { messages.data(), messages.size() } }, - { "state", { state.data(), state.size() } }, - { "visibility", visibility }, - { "account_data", { account_data.data(), account_data.size() } }, + { "room_id", room_id }, + { "membership", membership }, + { "state", states, }, + { "visibility", visibility }, + { "account_data", account_datas }, + { "messages", json::members + { + { "start", messages_start }, + { "chunk", messages_chunk }, + { "end", messages_end }, + }}, } }; }