diff --git a/modules/console.cc b/modules/console.cc index 68f05cd72..5b60a7463 100644 --- a/modules/console.cc +++ b/modules/console.cc @@ -3482,6 +3482,37 @@ console_cmd__feds__event(opt &out, const string_view &line) return true; } +bool +console_cmd__feds__head(opt &out, const string_view &line) +{ + const params param{line, " ", + { + "room_id", "[user_id]" + }}; + + const auto &room_id + { + m::room_id(param.at(0)) + }; + + const m::user::id &user_id + { + param.at(1, m::me.user_id) + }; + + using prototype = void (const m::room::id &, + const m::user::id &, + std::ostream &); + + static m::import feds__head + { + "federation_federation", "feds__head" + }; + + feds__head(room_id, user_id, out); + return true; +} + bool console_cmd__feds__resend(opt &out, const string_view &line) { diff --git a/modules/federation/federation.cc b/modules/federation/federation.cc index 667c2819b..a53cfb9e4 100644 --- a/modules/federation/federation.cc +++ b/modules/federation/federation.cc @@ -170,3 +170,78 @@ feds__event(const m::event::id &event_id, std::ostream &out) return; } + +extern "C" void +feds__head(const m::room::id &room_id, + const m::user::id &user_id, + std::ostream &out) +{ + struct req + :m::v1::make_join + { + char origin[256]; + char buf[16_KiB]; + + req(const m::room::id &room_id, const m::user::id &user_id, const string_view &origin) + :m::v1::make_join{[this, &room_id, &user_id, &origin] + { + m::v1::make_join::opts opts; + opts.remote = string_view{this->origin, strlcpy(this->origin, origin)}; + return m::v1::make_join{room_id, user_id, mutable_buffer{buf}, std::move(opts)}; + }()} + {} + }; + + std::list reqs; + const m::room::origins origins{room_id}; + origins.for_each([&out, &room_id, &user_id, &reqs] + (const string_view &origin) + { + const auto emsg + { + ircd::server::errmsg(origin) + }; + + if(emsg) + { + out << "! " << origin << " " << emsg << std::endl; + return; + } + + try + { + reqs.emplace_back(room_id, user_id, origin); + } + catch(const std::exception &e) + { + out << "! " << origin << " " << e.what() << std::endl; + return; + } + }); + + auto all + { + ctx::when_all(begin(reqs), end(reqs)) + }; + + all.wait(30s, std::nothrow); + + for(auto &req : reqs) try + { + if(req.wait(1ms, std::nothrow)) + { + const auto code{req.get()}; + const json::object &response{req}; + out << "+ " << std::setw(40) << std::left << req.origin + << " " << string_view{response} + << std::endl; + } + else cancel(req); + } + catch(const std::exception &e) + { + out << "- " << req.origin << " " << e.what() << std::endl; + } + + return; +}